From 05437e2a568177b34c94dc5ad24b8dcf3cbf586b Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Sun, 9 Nov 2014 11:17:46 +0000 Subject: [PATCH 01/47] #275: start on producer email. --- Gemfile | 2 +- Gemfile.lock | 6 +++++ .../admin/order_cycles_controller.rb | 21 +++++++++++++++ app/mailers/producer_mailer.rb | 13 +++++++++ app/views/admin/order_cycles/edit.html.haml | 4 +++ .../order_cycles/notifications.html.haml | 2 ++ .../order_cycle_report.html.haml | 27 +++++++++++++++++++ config/routes.rb | 2 ++ 8 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 app/mailers/producer_mailer.rb create mode 100644 app/views/admin/order_cycles/notifications.html.haml create mode 100644 app/views/producer_mailer/order_cycle_report.html.haml diff --git a/Gemfile b/Gemfile index 2e03d65a35..7ac484f4d0 100644 --- a/Gemfile +++ b/Gemfile @@ -43,7 +43,7 @@ gem 'spinjs-rails' gem 'rack-ssl', :require => 'rack/ssl' gem 'custom_error_message', :github => 'jeremydurham/custom-err-msg' gem 'angularjs-file-upload-rails', '~> 1.1.0' - +gem 'delayed_job_active_record' gem 'foreigner' gem 'immigrant' diff --git a/Gemfile.lock b/Gemfile.lock index c1a2c66522..3c36b410a8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -221,6 +221,11 @@ GEM debugger-ruby_core_source (~> 1.2.3) debugger-linecache (1.2.0) debugger-ruby_core_source (1.2.3) + delayed_job (4.0.4) + activesupport (>= 3.0, < 4.2) + delayed_job_active_record (4.0.2) + activerecord (>= 3.0, < 4.2) + delayed_job (>= 3.0, < 4.1) devise (2.2.8) bcrypt-ruby (~> 3.0) orm_adapter (~> 0.1) @@ -521,6 +526,7 @@ DEPENDENCIES db2fog debugger-linecache deface! + delayed_job_active_record factory_girl_rails foreigner foundation-icons-sass-rails diff --git a/app/controllers/admin/order_cycles_controller.rb b/app/controllers/admin/order_cycles_controller.rb index 63daf918de..f11b8c8dfa 100644 --- a/app/controllers/admin/order_cycles_controller.rb +++ b/app/controllers/admin/order_cycles_controller.rb @@ -70,6 +70,27 @@ module Admin redirect_to main_app.admin_order_cycles_path, :notice => "Your order cycle #{@order_cycle.name} has been cloned." end + OrderCycleNotificationJob = Struct.new(:order_cycle) do + def perform + puts order_cycle + @suppliers = order_cycle.suppliers + puts @suppliers + @suppliers.each { |supplier| ProducerMailer.order_cycle_report(supplier, order_cycle).deliver } + end + end + + # Send notifications to all producers who are part of the order cycle + def notifications + puts 'notify_producers!' + + @order_cycle = OrderCycle.find params[:id] + # Delayed::Job.enqueue OrderCycleNotificationJob.new(@order_cycle) + job = OrderCycleNotificationJob.new(@order_cycle) + job.perform + + render 'notifications' + end + protected def collection diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb new file mode 100644 index 0000000000..d479a20d5a --- /dev/null +++ b/app/mailers/producer_mailer.rb @@ -0,0 +1,13 @@ +require 'devise/mailers/helpers' +class ProducerMailer < ActionMailer::Base Spree::BaseMailer + include Devise::Mailers::Helpers + + def order_cycle_report(producer, order_cycle) + @producer = producer + @coordinator = order_cycle.coordinator + @order_cycle = order_cycle + subject = "[Open Food Network] Order cycle report for " + mail(to: @producer.email, from: from_address, subject: subject) + end + +end diff --git a/app/views/admin/order_cycles/edit.html.haml b/app/views/admin/order_cycles/edit.html.haml index 9bf0a8ca31..0f64420a83 100644 --- a/app/views/admin/order_cycles/edit.html.haml +++ b/app/views/admin/order_cycles/edit.html.haml @@ -1,4 +1,8 @@ %h1 Edit Order Cycle += content_for :page_actions do + %li + = button_to "Notify producers", main_app.admin_order_cycle_path + '/notifications', :id => 'admin_notify_producers' + = form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'order_cycle', 'ng-controller' => 'AdminEditOrderCycleCtrl', 'ng-submit' => 'submit()'} do |f| = render 'form', :f => f diff --git a/app/views/admin/order_cycles/notifications.html.haml b/app/views/admin/order_cycles/notifications.html.haml new file mode 100644 index 0000000000..b1e9e95f52 --- /dev/null +++ b/app/views/admin/order_cycles/notifications.html.haml @@ -0,0 +1,2 @@ + +Email sent. diff --git a/app/views/producer_mailer/order_cycle_report.html.haml b/app/views/producer_mailer/order_cycle_report.html.haml new file mode 100644 index 0000000000..0f67acf075 --- /dev/null +++ b/app/views/producer_mailer/order_cycle_report.html.haml @@ -0,0 +1,27 @@ +Dear #{@producer.name}, + +We now have all the consumer orders for the food drop on #{}. +Please deliver to #{coordinator.address} between 9:30am and 10:30am. If this is not convenient then please call #{@coordinator.phone}. + +NB If you have to arrange a different delivery day and time, the school has requested that you do not come on site during drop off/pick up times (8:45-9:15 and 15:00-15:30) + +Orders summary +============== + +Here is a summary of the orders for your products: + +- @order_cycle.exchange_for_distributor.each do |exchange| + + +Detailed orders breakdown +========================= + + + +Please confirm that you have got this email. + +Please send me an invoice for this amount so we can send you payment. + +If you need to phone on the day please call #{@coordinator.phone}. + +Thanks and best wishes - #{@coordinator.name} diff --git a/config/routes.rb b/config/routes.rb index ca4a6b59ff..2e5aa0ffc8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -40,6 +40,8 @@ Openfoodnetwork::Application.routes.draw do resources :order_cycles do post :bulk_update, on: :collection, as: :bulk_update get :clone, on: :member + + post 'notifications', on: :member end resources :enterprises do From 9b7fd1c16bc45b7efc2b067c4d504eb7120b50f3 Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Sun, 9 Nov 2014 11:19:26 +0000 Subject: [PATCH 02/47] #275: small tweaks. --- app/mailers/producer_mailer.rb | 13 +++++++++---- .../producer_mailer/order_cycle_report.html.haml | 6 +++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index d479a20d5a..6a8265f279 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -1,12 +1,17 @@ -require 'devise/mailers/helpers' -class ProducerMailer < ActionMailer::Base Spree::BaseMailer - include Devise::Mailers::Helpers + +class ProducerMailer < Spree::BaseMailer def order_cycle_report(producer, order_cycle) @producer = producer @coordinator = order_cycle.coordinator @order_cycle = order_cycle - subject = "[Open Food Network] Order cycle report for " + + # TODO: consider what happens if there is more than one distributor + first_producer = @order_cycle.distributors[0] + @distribution_date = @order_cycle.pickup_time_for first_producer + # puts @distribution_date + + subject = "[Open Food Network] Order cycle report for #{@distribution_date}" mail(to: @producer.email, from: from_address, subject: subject) end diff --git a/app/views/producer_mailer/order_cycle_report.html.haml b/app/views/producer_mailer/order_cycle_report.html.haml index 0f67acf075..3f19e7eb5f 100644 --- a/app/views/producer_mailer/order_cycle_report.html.haml +++ b/app/views/producer_mailer/order_cycle_report.html.haml @@ -1,7 +1,7 @@ Dear #{@producer.name}, -We now have all the consumer orders for the food drop on #{}. -Please deliver to #{coordinator.address} between 9:30am and 10:30am. If this is not convenient then please call #{@coordinator.phone}. +We now have all the consumer orders for the food drop on #{@distribution_date}. +Please deliver to #{@coordinator.address.address1}, #{@coordinator.address.city}, #{@coordinator.address.zipcode} during the regular delivery time. If this is not convenient then please call #{@coordinator.phone}. NB If you have to arrange a different delivery day and time, the school has requested that you do not come on site during drop off/pick up times (8:45-9:15 and 15:00-15:30) @@ -10,7 +10,7 @@ Orders summary Here is a summary of the orders for your products: -- @order_cycle.exchange_for_distributor.each do |exchange| +/ - @order_cycle.exchange_for_distributor.each do |exchange| Detailed orders breakdown From 375bdc0586ee8f3e1c7a97611ae9c6610de000ca Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Sun, 16 Nov 2014 07:14:29 +0000 Subject: [PATCH 03/47] #275: Change report format. Improved mailer. --- app/mailers/producer_mailer.rb | 25 +++++++++++---- ...html.haml => order_cycle_report.text.haml} | 21 ++++++------ spec/mailers/producer_mailer_spec.rb | 32 +++++++++++++++++++ 3 files changed, 62 insertions(+), 16 deletions(-) rename app/views/producer_mailer/{order_cycle_report.html.haml => order_cycle_report.text.haml} (59%) create mode 100644 spec/mailers/producer_mailer_spec.rb diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index 6a8265f279..9666ed8b0e 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -1,5 +1,6 @@ - +require 'devise/mailers/helpers' class ProducerMailer < Spree::BaseMailer + include Devise::Mailers::Helpers def order_cycle_report(producer, order_cycle) @producer = producer @@ -7,12 +8,24 @@ class ProducerMailer < Spree::BaseMailer @order_cycle = order_cycle # TODO: consider what happens if there is more than one distributor - first_producer = @order_cycle.distributors[0] - @distribution_date = @order_cycle.pickup_time_for first_producer - # puts @distribution_date + if @order_cycle.distributors.count > 0 + first_producer = @order_cycle.distributors[0] + @distribution_date = @order_cycle.pickup_time_for first_producer + end - subject = "[Open Food Network] Order cycle report for #{@distribution_date}" - mail(to: @producer.email, from: from_address, subject: subject) + subject = "[#{Spree::Config[:site_name]}] Order cycle report for #{@distribution_date}" + + @orders = Spree::Order.complete.not_state(:canceled).managed_by(@producer.owner) + @line_items = [] + @orders.each do |o| + @line_items += o.line_items.managed_by(@producer.owner) + end + + mail(to: @producer.email, + from: from_address, + subject: subject, + reply_to: @coordinator.email, + cc: @coordinator.email) end end diff --git a/app/views/producer_mailer/order_cycle_report.html.haml b/app/views/producer_mailer/order_cycle_report.text.haml similarity index 59% rename from app/views/producer_mailer/order_cycle_report.html.haml rename to app/views/producer_mailer/order_cycle_report.text.haml index 3f19e7eb5f..3e6767be7c 100644 --- a/app/views/producer_mailer/order_cycle_report.html.haml +++ b/app/views/producer_mailer/order_cycle_report.text.haml @@ -1,21 +1,22 @@ Dear #{@producer.name}, - +\ We now have all the consumer orders for the food drop on #{@distribution_date}. Please deliver to #{@coordinator.address.address1}, #{@coordinator.address.city}, #{@coordinator.address.zipcode} during the regular delivery time. If this is not convenient then please call #{@coordinator.phone}. -NB If you have to arrange a different delivery day and time, the school has requested that you do not come on site during drop off/pick up times (8:45-9:15 and 15:00-15:30) +Note: If you have to arrange a different delivery day and time, it is requested that you do not come on site during drop off/pick up times. +\ Orders summary -============== - +================ +\ Here is a summary of the orders for your products: +\ +- @line_items.each do |item| + #{item.variant.sku} #{raw(item.variant.product.supplier.name)} #{raw(item.variant.product.name)} #{raw(item.variant.options_text)} (QTY: #{item.quantity}) @ #{item.single_money} = #{item.display_amount} -/ - @order_cycle.exchange_for_distributor.each do |exchange| - - +\ Detailed orders breakdown -========================= - +=========================== Please confirm that you have got this email. @@ -23,5 +24,5 @@ Please confirm that you have got this email. Please send me an invoice for this amount so we can send you payment. If you need to phone on the day please call #{@coordinator.phone}. - +\ Thanks and best wishes - #{@coordinator.name} diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb new file mode 100644 index 0000000000..07ce507dc3 --- /dev/null +++ b/spec/mailers/producer_mailer_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe ProducerMailer do + let(:p) { create(:simple_product, supplier: s) } + let(:supplier) { create(:supplier_enterprise) } + let(:order_cycle) { create(:simple_order_cycle) } + + after do + ActionMailer::Base.deliveries.clear + end + + before do + ActionMailer::Base.delivery_method = :test + ActionMailer::Base.perform_deliveries = true + ActionMailer::Base.deliveries = [] + end + + it "should send an email when an order cycle is closed" do + ProducerMailer.order_cycle_report(supplier, order_cycle).deliver + ActionMailer::Base.deliveries.count.should == 3 + end + + it "sets a reply-to of the enterprise email" do + ProducerMailer.order_cycle_report(supplier, order_cycle).deliver + ActionMailer::Base.deliveries.last.reply_to.should == [supplier.email] + end + + it "ccs the enterprise" do + ProducerMailer.order_cycle_report(supplier, order_cycle).deliver + ActionMailer::Base.deliveries.last.cc.should == [supplier.email] + end +end From 803d790b7a83bcf44ec9a394169ebbb281566bfa Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Mon, 24 Nov 2014 21:00:36 +0000 Subject: [PATCH 04/47] Remove nokigiri warning. Tweak email subject. --- Gemfile | 2 ++ Gemfile.lock | 1 + app/mailers/producer_mailer.rb | 7 ++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 7ac484f4d0..5b1cf45f8d 100644 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,8 @@ ruby "1.9.3" gem 'rails', '3.2.19' +gem 'nokogiri' + gem 'pg' gem 'spree', :github => 'openfoodfoundation/spree', :branch => '1-3-stable' gem 'spree_i18n', :github => 'spree/spree_i18n' diff --git a/Gemfile.lock b/Gemfile.lock index 3c36b410a8..c97c7f940e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -546,6 +546,7 @@ DEPENDENCIES letter_opener momentjs-rails newrelic_rpm + nokogiri oj paperclip perftools.rb diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index 9666ed8b0e..ce7560b946 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -1,4 +1,5 @@ require 'devise/mailers/helpers' + class ProducerMailer < Spree::BaseMailer include Devise::Mailers::Helpers @@ -7,14 +8,14 @@ class ProducerMailer < Spree::BaseMailer @coordinator = order_cycle.coordinator @order_cycle = order_cycle - # TODO: consider what happens if there is more than one distributor + subject = "[#{Spree::Config[:site_name]}] Order cycle report" + if @order_cycle.distributors.count > 0 first_producer = @order_cycle.distributors[0] @distribution_date = @order_cycle.pickup_time_for first_producer + subject += " for #{@distribution_date}" if @distribution_date.size > 0 end - subject = "[#{Spree::Config[:site_name]}] Order cycle report for #{@distribution_date}" - @orders = Spree::Order.complete.not_state(:canceled).managed_by(@producer.owner) @line_items = [] @orders.each do |o| From 8d5a0aea9f96539db425b3f57670b287853388aa Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Mon, 24 Nov 2014 21:25:58 +0000 Subject: [PATCH 05/47] Setup daemon and delayed job table. --- Gemfile | 1 + Gemfile.lock | 2 ++ .../admin/order_cycles_controller.rb | 8 +------ .../20141124210549_create_delayed_jobs.rb | 22 +++++++++++++++++++ db/schema.rb | 18 ++++++++++++++- script/delayed_job | 5 +++++ 6 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 db/migrate/20141124210549_create_delayed_jobs.rb create mode 100755 script/delayed_job diff --git a/Gemfile b/Gemfile index 5b1cf45f8d..2a32c245a0 100644 --- a/Gemfile +++ b/Gemfile @@ -46,6 +46,7 @@ gem 'rack-ssl', :require => 'rack/ssl' gem 'custom_error_message', :github => 'jeremydurham/custom-err-msg' gem 'angularjs-file-upload-rails', '~> 1.1.0' gem 'delayed_job_active_record' +gem 'daemons' gem 'foreigner' gem 'immigrant' diff --git a/Gemfile.lock b/Gemfile.lock index c97c7f940e..43040891ef 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -209,6 +209,7 @@ GEM compass (>= 0.12.2, < 0.14) crack (0.4.1) safe_yaml (~> 0.9.0) + daemons (1.1.9) dalli (2.7.2) database_cleaner (0.7.1) db2fog (0.8.0) @@ -521,6 +522,7 @@ DEPENDENCIES comfortable_mexican_sofa compass-rails custom_error_message! + daemons dalli database_cleaner (= 0.7.1) db2fog diff --git a/app/controllers/admin/order_cycles_controller.rb b/app/controllers/admin/order_cycles_controller.rb index f11b8c8dfa..c412a79654 100644 --- a/app/controllers/admin/order_cycles_controller.rb +++ b/app/controllers/admin/order_cycles_controller.rb @@ -72,21 +72,15 @@ module Admin OrderCycleNotificationJob = Struct.new(:order_cycle) do def perform - puts order_cycle @suppliers = order_cycle.suppliers - puts @suppliers @suppliers.each { |supplier| ProducerMailer.order_cycle_report(supplier, order_cycle).deliver } end end # Send notifications to all producers who are part of the order cycle def notifications - puts 'notify_producers!' - @order_cycle = OrderCycle.find params[:id] - # Delayed::Job.enqueue OrderCycleNotificationJob.new(@order_cycle) - job = OrderCycleNotificationJob.new(@order_cycle) - job.perform + Delayed::Job.enqueue OrderCycleNotificationJob.new(@order_cycle) render 'notifications' end diff --git a/db/migrate/20141124210549_create_delayed_jobs.rb b/db/migrate/20141124210549_create_delayed_jobs.rb new file mode 100644 index 0000000000..f7de70bdc5 --- /dev/null +++ b/db/migrate/20141124210549_create_delayed_jobs.rb @@ -0,0 +1,22 @@ +class CreateDelayedJobs < ActiveRecord::Migration + def self.up + create_table :delayed_jobs, :force => true do |table| + table.integer :priority, :default => 0, :null => false # Allows some jobs to jump to the front of the queue + table.integer :attempts, :default => 0, :null => false # Provides for retries, but still fail eventually. + table.text :handler, :null => false # YAML-encoded string of the object that will do work + table.text :last_error # reason for last failure (See Note below) + table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future. + table.datetime :locked_at # Set when a client is working on this object + table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead) + table.string :locked_by # Who is working on this object (if locked) + table.string :queue # The name of the queue this job is in + table.timestamps + end + + add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority' + end + + def self.down + drop_table :delayed_jobs + end +end diff --git a/db/schema.rb b/db/schema.rb index 114dcd6b73..ad02712de3 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 => 20141010043405) do +ActiveRecord::Schema.define(:version => 20141124210549) do create_table "adjustment_metadata", :force => true do |t| t.integer "adjustment_id" @@ -155,6 +155,22 @@ ActiveRecord::Schema.define(:version => 20141010043405) do add_index "coordinator_fees", ["enterprise_fee_id"], :name => "index_coordinator_fees_on_enterprise_fee_id" add_index "coordinator_fees", ["order_cycle_id"], :name => "index_coordinator_fees_on_order_cycle_id" + create_table "delayed_jobs", :force => true do |t| + t.integer "priority", :default => 0, :null => false + t.integer "attempts", :default => 0, :null => false + t.text "handler", :null => false + t.text "last_error" + t.datetime "run_at" + t.datetime "locked_at" + t.datetime "failed_at" + t.string "locked_by" + t.string "queue" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority" + create_table "distributors_payment_methods", :id => false, :force => true do |t| t.integer "distributor_id" t.integer "payment_method_id" diff --git a/script/delayed_job b/script/delayed_job new file mode 100755 index 0000000000..edf195985f --- /dev/null +++ b/script/delayed_job @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby + +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) +require 'delayed/command' +Delayed::Command.new(ARGV).daemonize From 67b17de695ae000dc81501a0440a1b6e42798d68 Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Tue, 30 Dec 2014 11:33:13 +0000 Subject: [PATCH 06/47] #275: Add receival time and instructions to order cycle for incoming exchanges. Fix issues from feedback. --- .../admin/order_cycles_controller.rb | 10 ------ app/jobs/order_cycle_notification_job.rb | 8 +++++ app/mailers/producer_mailer.rb | 25 ++++++++------ .../order_cycles/_exchange_form.html.haml | 5 +++ app/views/admin/order_cycles/_form.html.haml | 1 + app/views/admin/order_cycles/edit.html.haml | 2 +- app/views/admin/order_cycles/show.rep | 3 ++ config/application.rb | 5 ++- ...229094516_add_receival_time_to_exchange.rb | 6 ++++ db/schema.rb | 4 ++- .../order_cycle_form_applicator.rb | 20 +++++++---- spec/mailers/order_mailer_spec.rb | 2 +- spec/mailers/producer_mailer_spec.rb | 33 ++++++++++++++----- 13 files changed, 86 insertions(+), 38 deletions(-) create mode 100644 app/jobs/order_cycle_notification_job.rb create mode 100644 db/migrate/20141229094516_add_receival_time_to_exchange.rb diff --git a/app/controllers/admin/order_cycles_controller.rb b/app/controllers/admin/order_cycles_controller.rb index c412a79654..dc9033e5bc 100644 --- a/app/controllers/admin/order_cycles_controller.rb +++ b/app/controllers/admin/order_cycles_controller.rb @@ -44,7 +44,6 @@ module Admin respond_to do |format| if @order_cycle.update_attributes(params[:order_cycle]) OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, order_cycle_permitted_enterprises).go! - flash[:notice] = 'Your order cycle has been updated.' format.html { redirect_to admin_order_cycles_path } format.json { render :json => {:success => true} } @@ -70,19 +69,10 @@ module Admin redirect_to main_app.admin_order_cycles_path, :notice => "Your order cycle #{@order_cycle.name} has been cloned." end - OrderCycleNotificationJob = Struct.new(:order_cycle) do - def perform - @suppliers = order_cycle.suppliers - @suppliers.each { |supplier| ProducerMailer.order_cycle_report(supplier, order_cycle).deliver } - end - end - # Send notifications to all producers who are part of the order cycle def notifications @order_cycle = OrderCycle.find params[:id] Delayed::Job.enqueue OrderCycleNotificationJob.new(@order_cycle) - - render 'notifications' end diff --git a/app/jobs/order_cycle_notification_job.rb b/app/jobs/order_cycle_notification_job.rb new file mode 100644 index 0000000000..2e66a31da5 --- /dev/null +++ b/app/jobs/order_cycle_notification_job.rb @@ -0,0 +1,8 @@ + +OrderCycleNotificationJob = Struct.new(:order_cycle) do + def perform + @suppliers = order_cycle.suppliers + @suppliers.each { |supplier| ProducerMailer.order_cycle_report(supplier, order_cycle).deliver } + end +end + diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index ce7560b946..ee586892db 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -1,7 +1,5 @@ -require 'devise/mailers/helpers' class ProducerMailer < Spree::BaseMailer - include Devise::Mailers::Helpers def order_cycle_report(producer, order_cycle) @producer = producer @@ -10,16 +8,23 @@ class ProducerMailer < Spree::BaseMailer subject = "[#{Spree::Config[:site_name]}] Order cycle report" - if @order_cycle.distributors.count > 0 - first_producer = @order_cycle.distributors[0] - @distribution_date = @order_cycle.pickup_time_for first_producer - subject += " for #{@distribution_date}" if @distribution_date.size > 0 - end + # if @order_cycle.distributors.any? + # first_producer = @order_cycle.distributors.first + # @distribution_date = @order_cycle.pickup_time_for first_producer + # subject += " for #{@distribution_date}" if @distribution_date.present? + # end + # TODO: what if producer handling orders into multiple order cycles? @orders = Spree::Order.complete.not_state(:canceled).managed_by(@producer.owner) - @line_items = [] - @orders.each do |o| - @line_items += o.line_items.managed_by(@producer.owner) + # puts @orders.size + + # Create a single flat list of all line items + @line_items = @orders.map(&:line_items).flatten + # Arrange the items in a hash to group quantities + @line_items.inject({}) do |lis, li| + lis[li.variant] ||= {line_item: li, quantity: 0} + lis[li.variant][:quantity] += li.quantity + lis end mail(to: @producer.email, diff --git a/app/views/admin/order_cycles/_exchange_form.html.haml b/app/views/admin/order_cycles/_exchange_form.html.haml index 8f81b9f03f..45c7bf0621 100644 --- a/app/views/admin/order_cycles/_exchange_form.html.haml +++ b/app/views/admin/order_cycles/_exchange_form.html.haml @@ -7,6 +7,11 @@ - else {{ incomingExchangesVariants().length }} selected +- if type == 'supplier' + %td.receival-details + = text_field_tag 'order_cycle_incoming_exchange_{{ $index }}_receival_time', '', 'id' => 'order_cycle_incoming_exchange_{{ $index }}_receival_time', 'placeholder' => 'Receive at (ie. Date / Time)', 'ng-model' => 'exchange.receival_time' + %br/ + = text_field_tag 'order_cycle_incoming_exchange_{{ $index }}_receival_instructions', '', 'id' => 'order_cycle_incoming_exchange_{{ $index }}_receival_instructions', 'placeholder' => 'Receival instructions', 'ng-model' => 'exchange.receival_instructions' - if type == 'distributor' %td.collection-details = text_field_tag 'order_cycle_outgoing_exchange_{{ $index }}_pickup_time', '', 'id' => 'order_cycle_outgoing_exchange_{{ $index }}_pickup_time', 'placeholder' => 'Ready for (ie. Date / Time)', 'ng-model' => 'exchange.pickup_time' diff --git a/app/views/admin/order_cycles/_form.html.haml b/app/views/admin/order_cycles/_form.html.haml index e859374a3b..b84b8e6853 100644 --- a/app/views/admin/order_cycles/_form.html.haml +++ b/app/views/admin/order_cycles/_form.html.haml @@ -17,6 +17,7 @@ %tr %th Supplier %th Products + %th Receival details %th Fees %th.actions %tbody{'ng-repeat' => 'exchange in order_cycle.incoming_exchanges'} diff --git a/app/views/admin/order_cycles/edit.html.haml b/app/views/admin/order_cycles/edit.html.haml index 0f64420a83..62cefcfd09 100644 --- a/app/views/admin/order_cycles/edit.html.haml +++ b/app/views/admin/order_cycles/edit.html.haml @@ -2,7 +2,7 @@ = content_for :page_actions do %li - = button_to "Notify producers", main_app.admin_order_cycle_path + '/notifications', :id => 'admin_notify_producers' + = button_to "Notify producers", main_app.notifications_admin_order_cycle_path, :id => 'admin_notify_producers' = form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'order_cycle', 'ng-controller' => 'AdminEditOrderCycleCtrl', 'ng-submit' => 'submit()'} do |f| = render 'form', :f => f diff --git a/app/views/admin/order_cycles/show.rep b/app/views/admin/order_cycles/show.rep index fb71602eb6..eb0f480982 100644 --- a/app/views/admin/order_cycles/show.rep +++ b/app/views/admin/order_cycles/show.rep @@ -22,6 +22,9 @@ r.element :order_cycle, @order_cycle do r.element :enterprise_id end + r.element :receival_time + r.element :receival_instructions + r.element :pickup_time r.element :pickup_instructions end diff --git a/config/application.rb b/config/application.rb index 1cddfcf3a1..0d87f37429 100644 --- a/config/application.rb +++ b/config/application.rb @@ -46,7 +46,10 @@ module Openfoodnetwork # -- all .rb files in that directory are automatically loaded. # Custom directories with classes and modules you want to be autoloadable. - config.autoload_paths += %W(#{config.root}/app/presenters) + config.autoload_paths += %W( + #{config.root}/app/presenters + #{config.root}/app/jobs + ) # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. diff --git a/db/migrate/20141229094516_add_receival_time_to_exchange.rb b/db/migrate/20141229094516_add_receival_time_to_exchange.rb new file mode 100644 index 0000000000..06933ed051 --- /dev/null +++ b/db/migrate/20141229094516_add_receival_time_to_exchange.rb @@ -0,0 +1,6 @@ +class AddReceivalTimeToExchange < ActiveRecord::Migration + def change + add_column :exchanges, :receival_time, :string + add_column :exchanges, :receival_instructions, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index ad02712de3..fab3de9a6a 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 => 20141124210549) do +ActiveRecord::Schema.define(:version => 20141229094516) do create_table "adjustment_metadata", :force => true do |t| t.integer "adjustment_id" @@ -323,6 +323,8 @@ ActiveRecord::Schema.define(:version => 20141124210549) do t.datetime "created_at", :null => false t.datetime "updated_at", :null => false t.boolean "incoming", :default => false, :null => false + t.string "receival_time" + t.string "receival_instructions" end add_index "exchanges", ["order_cycle_id"], :name => "index_exchanges_on_order_cycle_id" diff --git a/lib/open_food_network/order_cycle_form_applicator.rb b/lib/open_food_network/order_cycle_form_applicator.rb index 6556223dac..187690019f 100644 --- a/lib/open_food_network/order_cycle_form_applicator.rb +++ b/lib/open_food_network/order_cycle_form_applicator.rb @@ -21,10 +21,14 @@ module OpenFoodNetwork if exchange_exists?(exchange[:enterprise_id], @order_cycle.coordinator_id, true) update_exchange(exchange[:enterprise_id], @order_cycle.coordinator_id, true, - {variant_ids: variant_ids, enterprise_fee_ids: enterprise_fee_ids}) + {variant_ids: variant_ids, enterprise_fee_ids: enterprise_fee_ids, + receival_time: exchange[:receival_time], + receival_instructions: exchange[:receival_instructions]}) else add_exchange(exchange[:enterprise_id], @order_cycle.coordinator_id, true, - {variant_ids: variant_ids, enterprise_fee_ids: enterprise_fee_ids}) + {variant_ids: variant_ids, enterprise_fee_ids: enterprise_fee_ids, + receival_time: exchange[:receival_time], + receival_instructions: exchange[:receival_instructions],}) end end @@ -35,12 +39,16 @@ module OpenFoodNetwork if exchange_exists?(@order_cycle.coordinator_id, exchange[:enterprise_id], false) update_exchange(@order_cycle.coordinator_id, exchange[:enterprise_id], false, - {variant_ids: variant_ids, enterprise_fee_ids: enterprise_fee_ids, - pickup_time: exchange[:pickup_time], pickup_instructions: exchange[:pickup_instructions]}) + {variant_ids: variant_ids, + enterprise_fee_ids: enterprise_fee_ids, + pickup_time: exchange[:pickup_time], + pickup_instructions: exchange[:pickup_instructions]}) else add_exchange(@order_cycle.coordinator_id, exchange[:enterprise_id], false, - {variant_ids: variant_ids, enterprise_fee_ids: enterprise_fee_ids, - pickup_time: exchange[:pickup_time], pickup_instructions: exchange[:pickup_instructions]}) + {variant_ids: variant_ids, + enterprise_fee_ids: enterprise_fee_ids, + pickup_time: exchange[:pickup_time], + pickup_instructions: exchange[:pickup_instructions]}) end end diff --git a/spec/mailers/order_mailer_spec.rb b/spec/mailers/order_mailer_spec.rb index 0fae742ef9..ae4cdf9c98 100644 --- a/spec/mailers/order_mailer_spec.rb +++ b/spec/mailers/order_mailer_spec.rb @@ -22,7 +22,7 @@ describe Spree::OrderMailer do it "should send an email when given an order" do Spree::OrderMailer.confirm_email(@order1.id).deliver - ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.count.should == 3 end it "sets a reply-to of the enterprise email" do diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb index 07ce507dc3..2722be1ddb 100644 --- a/spec/mailers/producer_mailer_spec.rb +++ b/spec/mailers/producer_mailer_spec.rb @@ -1,20 +1,24 @@ require 'spec_helper' describe ProducerMailer do - let(:p) { create(:simple_product, supplier: s) } + let(:supplier) { create(:supplier_enterprise) } + let(:product) { create(:simple_product, supplier: supplier) } + let(:distributor) { create(:distributor_enterprise) } let(:supplier) { create(:supplier_enterprise) } let(:order_cycle) { create(:simple_order_cycle) } + let(:order) { create(:order, order_cycle: order_cycle, distributor: distributor) } + + before do + # ActionMailer::Base.delivery_method = :test + # ActionMailer::Base.perform_deliveries = true + ActionMailer::Base.deliveries.clear + order.set_order_cycle! order_cycle + end after do ActionMailer::Base.deliveries.clear end - before do - ActionMailer::Base.delivery_method = :test - ActionMailer::Base.perform_deliveries = true - ActionMailer::Base.deliveries = [] - end - it "should send an email when an order cycle is closed" do ProducerMailer.order_cycle_report(supplier, order_cycle).deliver ActionMailer::Base.deliveries.count.should == 3 @@ -25,8 +29,21 @@ describe ProducerMailer do ActionMailer::Base.deliveries.last.reply_to.should == [supplier.email] end - it "ccs the enterprise" do + it "cc's the enterprise" do ProducerMailer.order_cycle_report(supplier, order_cycle).deliver ActionMailer::Base.deliveries.last.cc.should == [supplier.email] end + + it "contains an aggregated list of produce" do + puts order.to_yaml + order.state= 'complete' + puts order.to_yaml + puts Spree::Order.complete.not_state(:canceled).size + # puts order_cycle.orders + # puts order.class + # puts order.class.instance_methods.sort + # puts order.managed_by supplier + ProducerMailer.order_cycle_report(supplier, order_cycle).deliver + puts ActionMailer::Base.deliveries.last.body + end end From 717b3b6494c5192b4a100c5917d97de66acad5fe Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Tue, 10 Mar 2015 19:19:57 +0000 Subject: [PATCH 07/47] #275: Fixes for testing aggregated orders. --- app/mailers/producer_mailer.rb | 2 +- .../order_cycle_report.text.haml | 4 +- spec/mailers/producer_mailer_spec.rb | 53 ++++++++++--------- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index ee586892db..9d8f6fe1bc 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -21,7 +21,7 @@ class ProducerMailer < Spree::BaseMailer # Create a single flat list of all line items @line_items = @orders.map(&:line_items).flatten # Arrange the items in a hash to group quantities - @line_items.inject({}) do |lis, li| + @line_items = @line_items.inject({}) do |lis, li| lis[li.variant] ||= {line_item: li, quantity: 0} lis[li.variant][:quantity] += li.quantity lis diff --git a/app/views/producer_mailer/order_cycle_report.text.haml b/app/views/producer_mailer/order_cycle_report.text.haml index 3e6767be7c..0b50e59d4a 100644 --- a/app/views/producer_mailer/order_cycle_report.text.haml +++ b/app/views/producer_mailer/order_cycle_report.text.haml @@ -11,8 +11,8 @@ Orders summary \ Here is a summary of the orders for your products: \ -- @line_items.each do |item| - #{item.variant.sku} #{raw(item.variant.product.supplier.name)} #{raw(item.variant.product.name)} #{raw(item.variant.options_text)} (QTY: #{item.quantity}) @ #{item.single_money} = #{item.display_amount} +- @line_items.each_pair do |variant, data| + #{variant.sku} #{raw(variant.product.supplier.name)} #{raw(variant.product.name)} #{raw(variant.options_text)} (QTY: #{data[:quantity]}) @ #{data[:line_item].single_money} = #{variant.display_amount} \ Detailed orders breakdown diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb index 2722be1ddb..33b52d0985 100644 --- a/spec/mailers/producer_mailer_spec.rb +++ b/spec/mailers/producer_mailer_spec.rb @@ -1,18 +1,25 @@ require 'spec_helper' describe ProducerMailer do - let(:supplier) { create(:supplier_enterprise) } - let(:product) { create(:simple_product, supplier: supplier) } - let(:distributor) { create(:distributor_enterprise) } - let(:supplier) { create(:supplier_enterprise) } + let(:s1) { create(:supplier_enterprise, address: create(:address)) } + let(:s2) { create(:supplier_enterprise, address: create(:address)) } + let(:d1) { create(:distributor_enterprise, address: create(:address)) } + let(:d2) { create(:distributor_enterprise, address: create(:address)) } + let(:p1) { create(:product, price: 12.34, distributors: [d1], supplier: s1) } + let(:p2) { create(:product, price: 23.45, distributors: [d2], supplier: s2) } let(:order_cycle) { create(:simple_order_cycle) } - let(:order) { create(:order, order_cycle: order_cycle, distributor: distributor) } + let!(:order) do + order = create(:order, distributor: d1, order_cycle: order_cycle, state: 'complete') + order.line_items << create(:line_item, variant: p1.master) + order.line_items << create(:line_item, variant: p1.master) + order.line_items << create(:line_item, variant: p2.master) + order.finalize! + order.save + order + end before do - # ActionMailer::Base.delivery_method = :test - # ActionMailer::Base.perform_deliveries = true ActionMailer::Base.deliveries.clear - order.set_order_cycle! order_cycle end after do @@ -20,30 +27,28 @@ describe ProducerMailer do end it "should send an email when an order cycle is closed" do - ProducerMailer.order_cycle_report(supplier, order_cycle).deliver - ActionMailer::Base.deliveries.count.should == 3 + ProducerMailer.order_cycle_report(s1, order_cycle).deliver + puts ActionMailer::Base.deliveries + ActionMailer::Base.deliveries.count.should == 1 end it "sets a reply-to of the enterprise email" do - ProducerMailer.order_cycle_report(supplier, order_cycle).deliver - ActionMailer::Base.deliveries.last.reply_to.should == [supplier.email] + ProducerMailer.order_cycle_report(s1, order_cycle).deliver + ActionMailer::Base.deliveries.last.reply_to.should == [s1.email] end it "cc's the enterprise" do - ProducerMailer.order_cycle_report(supplier, order_cycle).deliver - ActionMailer::Base.deliveries.last.cc.should == [supplier.email] + ProducerMailer.order_cycle_report(s1, order_cycle).deliver + ActionMailer::Base.deliveries.last.cc.should == [s1.email] end it "contains an aggregated list of produce" do - puts order.to_yaml - order.state= 'complete' - puts order.to_yaml - puts Spree::Order.complete.not_state(:canceled).size - # puts order_cycle.orders - # puts order.class - # puts order.class.instance_methods.sort - # puts order.managed_by supplier - ProducerMailer.order_cycle_report(supplier, order_cycle).deliver - puts ActionMailer::Base.deliveries.last.body + ProducerMailer.order_cycle_report(s1, order_cycle).deliver + email_body = ActionMailer::Base.deliveries.last.body + email_body.to_s.each_line do |line| + if line.include? p1.name + line.include?('QTY: 2').should == true + end + end end end From 99709b53edf7e53ba3a7bf58959700230d57c2ca Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Sat, 11 Apr 2015 13:19:48 +0100 Subject: [PATCH 08/47] Change controller action to 'notify_producers'. Add flash message on completion. Simplify job variables. Improve mailer query. Spec for job. --- app/controllers/admin/order_cycles_controller.rb | 5 ++++- app/jobs/order_cycle_notification_job.rb | 3 +-- app/mailers/producer_mailer.rb | 9 ++++----- app/views/admin/order_cycles/edit.html.haml | 2 +- .../admin/order_cycles/notifications.html.haml | 2 -- .../producer_mailer/order_cycle_report.text.haml | 2 +- spec/jobs/order_cycle_notification_job_spec.rb | 14 ++++++++++++++ spec/mailers/producer_mailer_spec.rb | 4 ++-- 8 files changed, 27 insertions(+), 14 deletions(-) delete mode 100644 app/views/admin/order_cycles/notifications.html.haml create mode 100644 spec/jobs/order_cycle_notification_job_spec.rb diff --git a/app/controllers/admin/order_cycles_controller.rb b/app/controllers/admin/order_cycles_controller.rb index dc9033e5bc..5aacb9e03e 100644 --- a/app/controllers/admin/order_cycles_controller.rb +++ b/app/controllers/admin/order_cycles_controller.rb @@ -70,9 +70,12 @@ module Admin end # Send notifications to all producers who are part of the order cycle - def notifications + def notify_producers @order_cycle = OrderCycle.find params[:id] Delayed::Job.enqueue OrderCycleNotificationJob.new(@order_cycle) + + flash[:notice] = 'Emails to be sent to producers have been queued for sending.' + format.html { redirect_to admin_order_cycles_path } end diff --git a/app/jobs/order_cycle_notification_job.rb b/app/jobs/order_cycle_notification_job.rb index 2e66a31da5..ea8b09f1fe 100644 --- a/app/jobs/order_cycle_notification_job.rb +++ b/app/jobs/order_cycle_notification_job.rb @@ -1,8 +1,7 @@ OrderCycleNotificationJob = Struct.new(:order_cycle) do def perform - @suppliers = order_cycle.suppliers - @suppliers.each { |supplier| ProducerMailer.order_cycle_report(supplier, order_cycle).deliver } + order_cycle.suppliers.each { |supplier| ProducerMailer.order_cycle_report(supplier, order_cycle).deliver } end end diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index 9d8f6fe1bc..8cf4efacb1 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -14,12 +14,11 @@ class ProducerMailer < Spree::BaseMailer # subject += " for #{@distribution_date}" if @distribution_date.present? # end - # TODO: what if producer handling orders into multiple order cycles? - @orders = Spree::Order.complete.not_state(:canceled).managed_by(@producer.owner) - # puts @orders.size + @line_items = Spree::LineItem. + joins(:order => :order_cycle, :variant => :product). + where('order_cycles.id = ?', order_cycle). + where('spree_products.supplier_id = ?', producer) - # Create a single flat list of all line items - @line_items = @orders.map(&:line_items).flatten # Arrange the items in a hash to group quantities @line_items = @line_items.inject({}) do |lis, li| lis[li.variant] ||= {line_item: li, quantity: 0} diff --git a/app/views/admin/order_cycles/edit.html.haml b/app/views/admin/order_cycles/edit.html.haml index 05c53ab91d..af41002d1e 100644 --- a/app/views/admin/order_cycles/edit.html.haml +++ b/app/views/admin/order_cycles/edit.html.haml @@ -2,7 +2,7 @@ = content_for :page_actions do %li - = button_to "Notify producers", main_app.notifications_admin_order_cycle_path, :id => 'admin_notify_producers' + = button_to "Notify producers", main_app.notify_producers_admin_order_cycle_path, :id => 'admin_notify_producers' - ng_controller = order_cycles_simple_view ? 'AdminSimpleEditOrderCycleCtrl' : 'AdminEditOrderCycleCtrl' diff --git a/app/views/admin/order_cycles/notifications.html.haml b/app/views/admin/order_cycles/notifications.html.haml deleted file mode 100644 index b1e9e95f52..0000000000 --- a/app/views/admin/order_cycles/notifications.html.haml +++ /dev/null @@ -1,2 +0,0 @@ - -Email sent. diff --git a/app/views/producer_mailer/order_cycle_report.text.haml b/app/views/producer_mailer/order_cycle_report.text.haml index 0b50e59d4a..43723aafa3 100644 --- a/app/views/producer_mailer/order_cycle_report.text.haml +++ b/app/views/producer_mailer/order_cycle_report.text.haml @@ -12,7 +12,7 @@ Orders summary Here is a summary of the orders for your products: \ - @line_items.each_pair do |variant, data| - #{variant.sku} #{raw(variant.product.supplier.name)} #{raw(variant.product.name)} #{raw(variant.options_text)} (QTY: #{data[:quantity]}) @ #{data[:line_item].single_money} = #{variant.display_amount} + #{variant.sku} #{raw(variant.product.supplier.name)} #{raw(variant.product.name)} #{raw(variant.options_text)} (QTY: #{data[:quantity]}) @ #{data[:line_item].single_money} = #{data[:line_item].display_amount} \ Detailed orders breakdown diff --git a/spec/jobs/order_cycle_notification_job_spec.rb b/spec/jobs/order_cycle_notification_job_spec.rb new file mode 100644 index 0000000000..77fbf0c430 --- /dev/null +++ b/spec/jobs/order_cycle_notification_job_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' + +describe OrderCycleNotificationJob do + let(:order_cycle) { create(:order_cycle) } + + it 'sends a mail to each supplier' do + mail = double() + allow(mail).to receive(:deliver) + mailer = double('ProducerMailer') + expect(ProducerMailer).to receive(:order_cycle_report).twice.and_return(mail) + job = OrderCycleNotificationJob.new(order_cycle) + job.perform + end +end diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb index 33b52d0985..19a10f4336 100644 --- a/spec/mailers/producer_mailer_spec.rb +++ b/spec/mailers/producer_mailer_spec.rb @@ -5,8 +5,8 @@ describe ProducerMailer do let(:s2) { create(:supplier_enterprise, address: create(:address)) } let(:d1) { create(:distributor_enterprise, address: create(:address)) } let(:d2) { create(:distributor_enterprise, address: create(:address)) } - let(:p1) { create(:product, price: 12.34, distributors: [d1], supplier: s1) } - let(:p2) { create(:product, price: 23.45, distributors: [d2], supplier: s2) } + let(:p1) { create(:product, price: 12.34, supplier: s1) } + let(:p2) { create(:product, price: 23.45, supplier: s2) } let(:order_cycle) { create(:simple_order_cycle) } let!(:order) do order = create(:order, distributor: d1, order_cycle: order_cycle, state: 'complete') From 9103e83ce2a8419d2b48fe56127d0c1d601ee243 Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Sat, 11 Apr 2015 18:28:31 +0100 Subject: [PATCH 09/47] #275: spec test for controller method. Other small fixes. --- .../admin/order_cycles_controller.rb | 3 +-- config/routes.rb | 2 +- .../admin/order_cycles_controller_spec.rb | 27 +++++++++++++++++++ .../jobs/order_cycle_notification_job_spec.rb | 1 - 4 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 spec/controllers/admin/order_cycles_controller_spec.rb diff --git a/app/controllers/admin/order_cycles_controller.rb b/app/controllers/admin/order_cycles_controller.rb index 5aacb9e03e..394b189609 100644 --- a/app/controllers/admin/order_cycles_controller.rb +++ b/app/controllers/admin/order_cycles_controller.rb @@ -74,8 +74,7 @@ module Admin @order_cycle = OrderCycle.find params[:id] Delayed::Job.enqueue OrderCycleNotificationJob.new(@order_cycle) - flash[:notice] = 'Emails to be sent to producers have been queued for sending.' - format.html { redirect_to admin_order_cycles_path } + redirect_to main_app.admin_order_cycles_path, :notice => 'Emails to be sent to producers have been queued for sending.' end diff --git a/config/routes.rb b/config/routes.rb index 29c4f35246..b7c2d66b68 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -43,7 +43,7 @@ Openfoodnetwork::Application.routes.draw do post :bulk_update, on: :collection, as: :bulk_update get :clone, on: :member - post 'notifications', on: :member + post 'notify_producers', on: :member end resources :enterprises do diff --git a/spec/controllers/admin/order_cycles_controller_spec.rb b/spec/controllers/admin/order_cycles_controller_spec.rb new file mode 100644 index 0000000000..faa3e095ae --- /dev/null +++ b/spec/controllers/admin/order_cycles_controller_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +module Admin + describe OrderCyclesController do + include AuthenticationWorkflow + + let(:user) { create_enterprise_user } + let(:admin_user) do + user = create(:user) + user.spree_roles << Spree::Role.find_or_create_by_name!('admin') + user + end + let(:order_cycle) { create(:simple_order_cycle) } + + context 'order cycle has closed' do + it 'can notify producers' do + controller.stub spree_current_user: admin_user + expect(Delayed::Job).to receive(:enqueue).once + spree_post :notify_producers, {id: order_cycle.id} + + # TODO: is there a better variable to use? + expect(response).to redirect_to spree.admin_path + '/order_cycles' + flash[:notice].should == 'Emails to be sent to producers have been queued for sending.' + end + end + end +end diff --git a/spec/jobs/order_cycle_notification_job_spec.rb b/spec/jobs/order_cycle_notification_job_spec.rb index 77fbf0c430..3c90295955 100644 --- a/spec/jobs/order_cycle_notification_job_spec.rb +++ b/spec/jobs/order_cycle_notification_job_spec.rb @@ -6,7 +6,6 @@ describe OrderCycleNotificationJob do it 'sends a mail to each supplier' do mail = double() allow(mail).to receive(:deliver) - mailer = double('ProducerMailer') expect(ProducerMailer).to receive(:order_cycle_report).twice.and_return(mail) job = OrderCycleNotificationJob.new(order_cycle) job.perform From 0f1ec17698f8a6ff27139eb19c57f73488f72e5c Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Tue, 28 Apr 2015 16:08:26 +0100 Subject: [PATCH 10/47] #275: Use better path variable in test. --- spec/controllers/admin/order_cycles_controller_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/controllers/admin/order_cycles_controller_spec.rb b/spec/controllers/admin/order_cycles_controller_spec.rb index faa3e095ae..ac89f6545b 100644 --- a/spec/controllers/admin/order_cycles_controller_spec.rb +++ b/spec/controllers/admin/order_cycles_controller_spec.rb @@ -18,8 +18,7 @@ module Admin expect(Delayed::Job).to receive(:enqueue).once spree_post :notify_producers, {id: order_cycle.id} - # TODO: is there a better variable to use? - expect(response).to redirect_to spree.admin_path + '/order_cycles' + expect(response).to redirect_to admin_order_cycles_path flash[:notice].should == 'Emails to be sent to producers have been queued for sending.' end end From 36584f01778d21f340e666902a9ea391c7166fff Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 29 Apr 2015 14:46:20 +1000 Subject: [PATCH 11/47] Remove puts from specs, fix failing controller spec --- spec/controllers/admin/order_cycles_controller_spec.rb | 6 ++++-- spec/mailers/producer_mailer_spec.rb | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/controllers/admin/order_cycles_controller_spec.rb b/spec/controllers/admin/order_cycles_controller_spec.rb index 234ee0fe5c..e9b0f4ea95 100644 --- a/spec/controllers/admin/order_cycles_controller_spec.rb +++ b/spec/controllers/admin/order_cycles_controller_spec.rb @@ -108,14 +108,16 @@ module Admin before do controller.stub spree_current_user: admin_user - spree_post :notify_producers, {id: order_cycle.id} end it "enqueues a job" do - expect(Delayed::Job).to receive(:enqueue).once + expect do + spree_post :notify_producers, {id: order_cycle.id} + end.to enqueue_job OrderCycleNotificationJob end it "redirects back to the order cycles path with a success message" do + spree_post :notify_producers, {id: order_cycle.id} expect(response).to redirect_to admin_order_cycles_path flash[:notice].should == 'Emails to be sent to producers have been queued for sending.' end diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb index 19a10f4336..b059a2c85c 100644 --- a/spec/mailers/producer_mailer_spec.rb +++ b/spec/mailers/producer_mailer_spec.rb @@ -28,7 +28,6 @@ describe ProducerMailer do it "should send an email when an order cycle is closed" do ProducerMailer.order_cycle_report(s1, order_cycle).deliver - puts ActionMailer::Base.deliveries ActionMailer::Base.deliveries.count.should == 1 end From 713c93a570e5b162e9a7fcda1d30a5d87da9d138 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 29 Apr 2015 15:00:22 +1000 Subject: [PATCH 12/47] Fix OrderCycleFormApplicator specs --- lib/open_food_network/order_cycle_form_applicator.rb | 2 ++ .../open_food_network/order_cycle_form_applicator_spec.rb | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/open_food_network/order_cycle_form_applicator.rb b/lib/open_food_network/order_cycle_form_applicator.rb index 95afa6713a..540a18da13 100644 --- a/lib/open_food_network/order_cycle_form_applicator.rb +++ b/lib/open_food_network/order_cycle_form_applicator.rb @@ -1,3 +1,5 @@ +require 'open_food_network/order_cycle_permissions' + module OpenFoodNetwork # There are two translator classes on the boundary between Angular and Rails: On the Angular side, diff --git a/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb b/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb index 6a03964039..a9b6a0787b 100644 --- a/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb +++ b/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb @@ -11,7 +11,7 @@ module OpenFoodNetwork coordinator_id = 123 supplier_id = 456 - incoming_exchange = {:enterprise_id => supplier_id, :incoming => true, :variants => {'1' => true, '2' => false, '3' => true}, :enterprise_fee_ids => [1, 2]} + incoming_exchange = {:enterprise_id => supplier_id, :incoming => true, :variants => {'1' => true, '2' => false, '3' => true}, :enterprise_fee_ids => [1, 2], :receival_time => 'receival time', :receival_instructions => 'receival instructions'} oc = double(:order_cycle, :coordinator_id => coordinator_id, :exchanges => [], :incoming_exchanges => [incoming_exchange], :outgoing_exchanges => []) @@ -19,7 +19,7 @@ module OpenFoodNetwork applicator.should_receive(:incoming_exchange_variant_ids).with(incoming_exchange).and_return([1, 3]) applicator.should_receive(:exchange_exists?).with(supplier_id, coordinator_id, true).and_return(false) - applicator.should_receive(:add_exchange).with(supplier_id, coordinator_id, true, {:variant_ids => [1, 3], :enterprise_fee_ids => [1, 2]}) + applicator.should_receive(:add_exchange).with(supplier_id, coordinator_id, true, {:variant_ids => [1, 3], :enterprise_fee_ids => [1, 2], :receival_time => 'receival time', :receival_instructions => 'receival instructions'}) applicator.should_receive(:destroy_untouched_exchanges) applicator.go! @@ -47,7 +47,7 @@ module OpenFoodNetwork coordinator_id = 123 supplier_id = 456 - incoming_exchange = {:enterprise_id => supplier_id, :incoming => true, :variants => {'1' => true, '2' => false, '3' => true}, :enterprise_fee_ids => [1, 2]} + incoming_exchange = {:enterprise_id => supplier_id, :incoming => true, :variants => {'1' => true, '2' => false, '3' => true}, :enterprise_fee_ids => [1, 2], :receival_time => 'receival time', :receival_instructions => 'receival instructions'} oc = double(:order_cycle, :coordinator_id => coordinator_id, @@ -59,7 +59,7 @@ module OpenFoodNetwork applicator.should_receive(:incoming_exchange_variant_ids).with(incoming_exchange).and_return([1, 3]) applicator.should_receive(:exchange_exists?).with(supplier_id, coordinator_id, true).and_return(true) - applicator.should_receive(:update_exchange).with(supplier_id, coordinator_id, true, {:variant_ids => [1, 3], :enterprise_fee_ids => [1, 2]}) + applicator.should_receive(:update_exchange).with(supplier_id, coordinator_id, true, {:variant_ids => [1, 3], :enterprise_fee_ids => [1, 2], :receival_time => 'receival time', :receival_instructions => 'receival instructions'}) applicator.should_receive(:destroy_untouched_exchanges) applicator.go! From 4279742de50a49054de32282128734b9c7ca7209 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 29 Apr 2015 15:21:05 +1000 Subject: [PATCH 13/47] Avoid serialising entire order cycle when enqueuing OrderCycleNotificationJob --- app/controllers/admin/order_cycles_controller.rb | 3 +-- app/jobs/order_cycle_notification_job.rb | 5 ++--- spec/jobs/order_cycle_notification_job_spec.rb | 5 ++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/controllers/admin/order_cycles_controller.rb b/app/controllers/admin/order_cycles_controller.rb index 526b9d5976..8cc0aef9b4 100644 --- a/app/controllers/admin/order_cycles_controller.rb +++ b/app/controllers/admin/order_cycles_controller.rb @@ -80,8 +80,7 @@ module Admin # Send notifications to all producers who are part of the order cycle def notify_producers - @order_cycle = OrderCycle.find params[:id] - Delayed::Job.enqueue OrderCycleNotificationJob.new(@order_cycle) + Delayed::Job.enqueue OrderCycleNotificationJob.new(params[:id].to_i) redirect_to main_app.admin_order_cycles_path, :notice => 'Emails to be sent to producers have been queued for sending.' end diff --git a/app/jobs/order_cycle_notification_job.rb b/app/jobs/order_cycle_notification_job.rb index ea8b09f1fe..b18348813e 100644 --- a/app/jobs/order_cycle_notification_job.rb +++ b/app/jobs/order_cycle_notification_job.rb @@ -1,7 +1,6 @@ - -OrderCycleNotificationJob = Struct.new(:order_cycle) do +OrderCycleNotificationJob = Struct.new(:order_cycle_id) do def perform + order_cycle = OrderCycle.find order_cycle_id order_cycle.suppliers.each { |supplier| ProducerMailer.order_cycle_report(supplier, order_cycle).deliver } end end - diff --git a/spec/jobs/order_cycle_notification_job_spec.rb b/spec/jobs/order_cycle_notification_job_spec.rb index 3c90295955..4341035340 100644 --- a/spec/jobs/order_cycle_notification_job_spec.rb +++ b/spec/jobs/order_cycle_notification_job_spec.rb @@ -3,11 +3,10 @@ require 'spec_helper' describe OrderCycleNotificationJob do let(:order_cycle) { create(:order_cycle) } - it 'sends a mail to each supplier' do + it "sends a mail to each supplier" do mail = double() allow(mail).to receive(:deliver) expect(ProducerMailer).to receive(:order_cycle_report).twice.and_return(mail) - job = OrderCycleNotificationJob.new(order_cycle) - job.perform + run_job OrderCycleNotificationJob.new(order_cycle.id) end end From 30e04b509d0fabf1fa04ce028c8b850884c7d290 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 29 Apr 2015 15:31:13 +1000 Subject: [PATCH 14/47] Clean up routes --- config/routes.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index d4a16998b6..124802e5b3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -43,9 +43,11 @@ Openfoodnetwork::Application.routes.draw do namespace :admin do resources :order_cycles do post :bulk_update, on: :collection, as: :bulk_update - get :clone, on: :member - post 'notify_producers', on: :member + member do + get :clone + post :notify_producers + end end resources :enterprises do From 3a3bf19cf8372dc7b4b45067b33c317f8cd84241 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 29 Apr 2015 15:31:42 +1000 Subject: [PATCH 15/47] Clean up duplication --- spec/mailers/producer_mailer_spec.rb | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb index b059a2c85c..98d7171f0d 100644 --- a/spec/mailers/producer_mailer_spec.rb +++ b/spec/mailers/producer_mailer_spec.rb @@ -17,9 +17,11 @@ describe ProducerMailer do order.save order end + let(:mail) { ActionMailer::Base.deliveries.last } before do ActionMailer::Base.deliveries.clear + ProducerMailer.order_cycle_report(s1, order_cycle).deliver end after do @@ -27,26 +29,22 @@ describe ProducerMailer do end it "should send an email when an order cycle is closed" do - ProducerMailer.order_cycle_report(s1, order_cycle).deliver ActionMailer::Base.deliveries.count.should == 1 end it "sets a reply-to of the enterprise email" do - ProducerMailer.order_cycle_report(s1, order_cycle).deliver - ActionMailer::Base.deliveries.last.reply_to.should == [s1.email] + mail.reply_to.should == [s1.email] end it "cc's the enterprise" do - ProducerMailer.order_cycle_report(s1, order_cycle).deliver - ActionMailer::Base.deliveries.last.cc.should == [s1.email] + mail.cc.should == [s1.email] end it "contains an aggregated list of produce" do - ProducerMailer.order_cycle_report(s1, order_cycle).deliver - email_body = ActionMailer::Base.deliveries.last.body + email_body = mail.body email_body.to_s.each_line do |line| if line.include? p1.name - line.include?('QTY: 2').should == true + line.should include 'QTY: 2' end end end From 2fe5d7c73ff827204a949852a2c5c00d140ce136 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 29 Apr 2015 15:33:39 +1000 Subject: [PATCH 16/47] Remove commented code, use neater syntax for accessing Spree config var --- app/mailers/producer_mailer.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index 8cf4efacb1..a79860b9a1 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -6,13 +6,7 @@ class ProducerMailer < Spree::BaseMailer @coordinator = order_cycle.coordinator @order_cycle = order_cycle - subject = "[#{Spree::Config[:site_name]}] Order cycle report" - - # if @order_cycle.distributors.any? - # first_producer = @order_cycle.distributors.first - # @distribution_date = @order_cycle.pickup_time_for first_producer - # subject += " for #{@distribution_date}" if @distribution_date.present? - # end + subject = "[#{Spree::Config.site_name}] Order cycle report" @line_items = Spree::LineItem. joins(:order => :order_cycle, :variant => :product). From 6999bcfd4e6c343647259ec3721548be98b9b023 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 29 Apr 2015 15:43:50 +1000 Subject: [PATCH 17/47] Only include complete orders in producer mailer report --- app/mailers/producer_mailer.rb | 3 ++- spec/mailers/producer_mailer_spec.rb | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index a79860b9a1..1c3fef8653 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -11,7 +11,8 @@ class ProducerMailer < Spree::BaseMailer @line_items = Spree::LineItem. joins(:order => :order_cycle, :variant => :product). where('order_cycles.id = ?', order_cycle). - where('spree_products.supplier_id = ?', producer) + where('spree_products.supplier_id = ?', producer). + merge(Spree::Order.complete) # Arrange the items in a hash to group quantities @line_items = @line_items.inject({}) do |lis, li| diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb index 98d7171f0d..ddc7fb68f9 100644 --- a/spec/mailers/producer_mailer_spec.rb +++ b/spec/mailers/producer_mailer_spec.rb @@ -7,6 +7,7 @@ describe ProducerMailer do let(:d2) { create(:distributor_enterprise, address: create(:address)) } let(:p1) { create(:product, price: 12.34, supplier: s1) } let(:p2) { create(:product, price: 23.45, supplier: s2) } + let(:p3) { create(:product, price: 34.56, supplier: s1) } let(:order_cycle) { create(:simple_order_cycle) } let!(:order) do order = create(:order, distributor: d1, order_cycle: order_cycle, state: 'complete') @@ -17,6 +18,12 @@ describe ProducerMailer do order.save order end + let!(:order_incomplete) do + order = create(:order, distributor: d1, order_cycle: order_cycle, state: 'payment') + order.line_items << create(:line_item, variant: p3.master) + order.save + order + end let(:mail) { ActionMailer::Base.deliveries.last } before do @@ -24,10 +31,6 @@ describe ProducerMailer do ProducerMailer.order_cycle_report(s1, order_cycle).deliver end - after do - ActionMailer::Base.deliveries.clear - end - it "should send an email when an order cycle is closed" do ActionMailer::Base.deliveries.count.should == 1 end @@ -41,11 +44,14 @@ describe ProducerMailer do end it "contains an aggregated list of produce" do - email_body = mail.body - email_body.to_s.each_line do |line| + mail.body.to_s.each_line do |line| if line.include? p1.name line.should include 'QTY: 2' end end end + + it "does not include incomplete orders" do + mail.body.should_not include p3.name + end end From 3565548e910b0e3bbd1d79ff8c7b94f377e5addb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 29 Apr 2015 15:50:42 +1000 Subject: [PATCH 18/47] Extract data preparation into private methods --- app/mailers/producer_mailer.rb | 37 ++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index 1c3fef8653..e1a8953d36 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -5,22 +5,10 @@ class ProducerMailer < Spree::BaseMailer @producer = producer @coordinator = order_cycle.coordinator @order_cycle = order_cycle + @line_items = aggregated_line_items_from(@order_cycle, @producer) subject = "[#{Spree::Config.site_name}] Order cycle report" - @line_items = Spree::LineItem. - joins(:order => :order_cycle, :variant => :product). - where('order_cycles.id = ?', order_cycle). - where('spree_products.supplier_id = ?', producer). - merge(Spree::Order.complete) - - # Arrange the items in a hash to group quantities - @line_items = @line_items.inject({}) do |lis, li| - lis[li.variant] ||= {line_item: li, quantity: 0} - lis[li.variant][:quantity] += li.quantity - lis - end - mail(to: @producer.email, from: from_address, subject: subject, @@ -28,4 +16,27 @@ class ProducerMailer < Spree::BaseMailer cc: @coordinator.email) end + + private + + def aggregated_line_items_from(order_cycle, producer) + aggregate_line_items line_items_from(order_cycle, producer) + end + + def line_items_from(order_cycle, producer) + Spree::LineItem. + joins(:order => :order_cycle, :variant => :product). + where('order_cycles.id = ?', order_cycle). + merge(Spree::Product.in_supplier(producer)). + merge(Spree::Order.complete) + end + + def aggregate_line_items(line_items) + # Arrange the items in a hash to group quantities + line_items.inject({}) do |lis, li| + lis[li.variant] ||= {line_item: li, quantity: 0} + lis[li.variant][:quantity] += li.quantity + lis + end + end end From 73376b30e2e57318f08c4d0f3d40ae12efda023b Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 29 Apr 2015 15:56:27 +1000 Subject: [PATCH 19/47] Convention --- spec/jobs/order_cycle_notification_job_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/jobs/order_cycle_notification_job_spec.rb b/spec/jobs/order_cycle_notification_job_spec.rb index 4341035340..674bdbdd24 100644 --- a/spec/jobs/order_cycle_notification_job_spec.rb +++ b/spec/jobs/order_cycle_notification_job_spec.rb @@ -4,7 +4,7 @@ describe OrderCycleNotificationJob do let(:order_cycle) { create(:order_cycle) } it "sends a mail to each supplier" do - mail = double() + mail = double(:mail) allow(mail).to receive(:deliver) expect(ProducerMailer).to receive(:order_cycle_report).twice.and_return(mail) run_job OrderCycleNotificationJob.new(order_cycle.id) From 91ca5f02138e6c486da0fa5038c5ff8d24d4d851 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 1 May 2015 10:08:24 +1000 Subject: [PATCH 20/47] Fix specs for receival_time / instructions --- spec/factories.rb | 8 +++++--- spec/models/exchange_spec.rb | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/spec/factories.rb b/spec/factories.rb index c798999134..9e0829cce9 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -15,9 +15,11 @@ FactoryGirl.define do # Incoming Exchanges ex1 = create(:exchange, :order_cycle => oc, :incoming => true, - :sender => supplier1, :receiver => oc.coordinator) + :sender => supplier1, :receiver => oc.coordinator, + :receival_time => 'time 0', :receival_instructions => 'instructions 0') ex2 = create(:exchange, :order_cycle => oc, :incoming => true, - :sender => supplier2, :receiver => oc.coordinator) + :sender => supplier2, :receiver => oc.coordinator, + :receival_time => 'time 1', :receival_instructions => 'instructions 1') ExchangeFee.create!(exchange: ex1, enterprise_fee: create(:enterprise_fee, enterprise: ex1.sender)) ExchangeFee.create!(exchange: ex2, @@ -71,7 +73,7 @@ FactoryGirl.define do after(:create) do |oc, proxy| proxy.suppliers.each do |supplier| - ex = create(:exchange, :order_cycle => oc, :sender => supplier, :receiver => oc.coordinator, :incoming => true, :pickup_time => 'time', :pickup_instructions => 'instructions') + ex = create(:exchange, :order_cycle => oc, :sender => supplier, :receiver => oc.coordinator, :incoming => true, :receival_time => 'time', :receival_instructions => 'instructions') proxy.variants.each { |v| ex.variants << v } end diff --git a/spec/models/exchange_spec.rb b/spec/models/exchange_spec.rb index 82f360aa16..1297786750 100644 --- a/spec/models/exchange_spec.rb +++ b/spec/models/exchange_spec.rb @@ -277,6 +277,7 @@ describe Exchange do 'payment_enterprise_id' => exchange.payment_enterprise_id, 'variant_ids' => exchange.variant_ids.sort, 'enterprise_fee_ids' => exchange.enterprise_fee_ids.sort, 'pickup_time' => exchange.pickup_time, 'pickup_instructions' => exchange.pickup_instructions, + 'receival_time' => exchange.receival_time, 'receival_instructions' => exchange.receival_instructions, 'created_at' => exchange.created_at, 'updated_at' => exchange.updated_at} end @@ -286,7 +287,8 @@ describe Exchange do 'incoming' => exchange.incoming, 'payment_enterprise_id' => exchange.payment_enterprise_id, 'variant_ids' => exchange.variant_ids.sort, 'enterprise_fee_ids' => exchange.enterprise_fee_ids.sort, - 'pickup_time' => exchange.pickup_time, 'pickup_instructions' => exchange.pickup_instructions} + 'pickup_time' => exchange.pickup_time, 'pickup_instructions' => exchange.pickup_instructions, + 'receival_time' => exchange.receival_time, 'receival_instructions' => exchange.receival_instructions} end end From fd3732435941a365bd6187eeb8aa02d85067b0d2 Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Sat, 9 May 2015 11:02:25 +0100 Subject: [PATCH 21/47] #536: Add permissions checking for Notify producers action. --- app/models/spree/ability_decorator.rb | 2 +- app/views/admin/order_cycles/edit.html.haml | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index e66c03aa72..28aa0b5701 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -127,7 +127,7 @@ class AbilityDecorator can [:admin, :index, :read, :edit, :update], OrderCycle do |order_cycle| OrderCycle.accessible_by(user).include? order_cycle end - can [:bulk_update, :clone, :destroy], OrderCycle do |order_cycle| + can [:bulk_update, :clone, :destroy, :notify_producers], OrderCycle do |order_cycle| user.enterprises.include? order_cycle.coordinator end can [:for_order_cycle], Enterprise diff --git a/app/views/admin/order_cycles/edit.html.haml b/app/views/admin/order_cycles/edit.html.haml index d09b0e0ee0..71d58d162e 100644 --- a/app/views/admin/order_cycles/edit.html.haml +++ b/app/views/admin/order_cycles/edit.html.haml @@ -1,6 +1,7 @@ -= content_for :page_actions do - %li - = button_to "Notify producers", main_app.notify_producers_admin_order_cycle_path, :id => 'admin_notify_producers' +- if can? :notify_producers, @order_cycle + = content_for :page_actions do + %li + = button_to "Notify producers", main_app.notify_producers_admin_order_cycle_path, :id => 'admin_notify_producers' %h1 Edit Order Cycle From 2f05fc3824739989d08bfa61d9eacaf587309169 Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Sun, 24 May 2015 10:38:49 +0100 Subject: [PATCH 22/47] #275: Insert receival time and instructions into email. --- app/mailers/producer_mailer.rb | 2 ++ app/models/order_cycle.rb | 14 +++++++++++++- app/views/admin/order_cycles/edit.html.haml | 2 +- .../producer_mailer/order_cycle_report.text.haml | 6 +++++- spec/mailers/producer_mailer_spec.rb | 13 ++++++++++++- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index e1a8953d36..66de47a36b 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -6,6 +6,8 @@ class ProducerMailer < Spree::BaseMailer @coordinator = order_cycle.coordinator @order_cycle = order_cycle @line_items = aggregated_line_items_from(@order_cycle, @producer) + @receival_time = @order_cycle.receival_time_for @producer + @receival_instructions = @order_cycle.receival_instructions_for @producer subject = "[#{Spree::Config.site_name}] Order cycle report" diff --git a/app/models/order_cycle.rb b/app/models/order_cycle.rb index adcd596a8c..442014c0d7 100644 --- a/app/models/order_cycle.rb +++ b/app/models/order_cycle.rb @@ -26,7 +26,7 @@ class OrderCycle < ActiveRecord::Base closed. where("order_cycles.orders_close_at >= ?", 31.days.ago). order("order_cycles.orders_close_at DESC") } - + scope :soonest_opening, lambda { upcoming.order('order_cycles.orders_open_at ASC') } scope :distributing_product, lambda { |product| @@ -163,6 +163,18 @@ class OrderCycle < ActiveRecord::Base exchanges.outgoing.to_enterprises([distributor]).first end + def exchange_for_supplier(supplier) + exchanges.incoming.from_enterprises([supplier]).first + end + + def receival_time_for(supplier) + exchange_for_supplier(supplier).andand.receival_time + end + + def receival_instructions_for(supplier) + exchange_for_supplier(supplier).andand.receival_instructions + end + def pickup_time_for(distributor) exchange_for_distributor(distributor).andand.pickup_time || distributor.next_collection_at end diff --git a/app/views/admin/order_cycles/edit.html.haml b/app/views/admin/order_cycles/edit.html.haml index 71d58d162e..ab9c9c1b29 100644 --- a/app/views/admin/order_cycles/edit.html.haml +++ b/app/views/admin/order_cycles/edit.html.haml @@ -1,7 +1,7 @@ - if can? :notify_producers, @order_cycle = content_for :page_actions do %li - = button_to "Notify producers", main_app.notify_producers_admin_order_cycle_path, :id => 'admin_notify_producers' + = button_to "Notify producers", main_app.notify_producers_admin_order_cycle_path, :id => 'admin_notify_producers', :confirm => 'Are you sure?' %h1 Edit Order Cycle diff --git a/app/views/producer_mailer/order_cycle_report.text.haml b/app/views/producer_mailer/order_cycle_report.text.haml index 43723aafa3..f6bbec8712 100644 --- a/app/views/producer_mailer/order_cycle_report.text.haml +++ b/app/views/producer_mailer/order_cycle_report.text.haml @@ -1,6 +1,10 @@ Dear #{@producer.name}, \ -We now have all the consumer orders for the food drop on #{@distribution_date}. +We now have all the consumer orders for next food drop. Please drop off your delivery at #{@receival_time}. + +- if @receival_instructions + Extra instructions: #{@receival_instructions} + Please deliver to #{@coordinator.address.address1}, #{@coordinator.address.city}, #{@coordinator.address.zipcode} during the regular delivery time. If this is not convenient then please call #{@coordinator.phone}. Note: If you have to arrange a different delivery day and time, it is requested that you do not come on site during drop off/pick up times. diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb index ddc7fb68f9..bb6518545b 100644 --- a/spec/mailers/producer_mailer_spec.rb +++ b/spec/mailers/producer_mailer_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' - +require 'yaml' describe ProducerMailer do let(:s1) { create(:supplier_enterprise, address: create(:address)) } let(:s2) { create(:supplier_enterprise, address: create(:address)) } @@ -9,6 +9,8 @@ describe ProducerMailer do let(:p2) { create(:product, price: 23.45, supplier: s2) } let(:p3) { create(:product, price: 34.56, supplier: s1) } let(:order_cycle) { create(:simple_order_cycle) } + let!(:incoming_exchange) { order_cycle.exchanges.create! sender: s1, receiver: d1, incoming: true, receival_time: '10am Saturday', receival_instructions: 'Outside shed.' } + let!(:order) do order = create(:order, distributor: d1, order_cycle: order_cycle, state: 'complete') order.line_items << create(:line_item, variant: p1.master) @@ -39,6 +41,15 @@ describe ProducerMailer do mail.reply_to.should == [s1.email] end + it "includes receival time" do + mail.body.should include '10am Saturday' + end + + it "includes receival instructions" do + puts mail.body + mail.body.should include 'Outside shed.' + end + it "cc's the enterprise" do mail.cc.should == [s1.email] end From baaa192967c429d73fd5b39eb6d2642c6a9e6266 Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Sun, 24 May 2015 10:44:39 +0100 Subject: [PATCH 23/47] #275: Code cleanup. --- spec/mailers/producer_mailer_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb index bb6518545b..672976a43d 100644 --- a/spec/mailers/producer_mailer_spec.rb +++ b/spec/mailers/producer_mailer_spec.rb @@ -1,5 +1,6 @@ require 'spec_helper' require 'yaml' + describe ProducerMailer do let(:s1) { create(:supplier_enterprise, address: create(:address)) } let(:s2) { create(:supplier_enterprise, address: create(:address)) } @@ -46,7 +47,6 @@ describe ProducerMailer do end it "includes receival instructions" do - puts mail.body mail.body.should include 'Outside shed.' end From 421774e46c88c3c82a9d2a7fe0cefde385727659 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Sat, 17 Oct 2015 11:02:47 +1100 Subject: [PATCH 24/47] Do not send producer notifications when the producer has no orders for this order cycle --- app/mailers/producer_mailer.rb | 19 ++++++++++++------- spec/mailers/producer_mailer_spec.rb | 15 +++++++++++---- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index 66de47a36b..1f021657b1 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -1,4 +1,3 @@ - class ProducerMailer < Spree::BaseMailer def order_cycle_report(producer, order_cycle) @@ -9,18 +8,24 @@ class ProducerMailer < Spree::BaseMailer @receival_time = @order_cycle.receival_time_for @producer @receival_instructions = @order_cycle.receival_instructions_for @producer - subject = "[#{Spree::Config.site_name}] Order cycle report" + subject = "[#{Spree::Config.site_name}] Order cycle report for #{producer.name}" - mail(to: @producer.email, - from: from_address, - subject: subject, - reply_to: @coordinator.email, - cc: @coordinator.email) + if has_orders? order_cycle, producer + mail(to: @producer.email, + from: from_address, + subject: subject, + reply_to: @coordinator.email, + cc: @coordinator.email) + end end private + def has_orders?(order_cycle, producer) + line_items_from(order_cycle, producer).any? + end + def aggregated_line_items_from(order_cycle, producer) aggregate_line_items line_items_from(order_cycle, producer) end diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb index 672976a43d..e5ace458d2 100644 --- a/spec/mailers/producer_mailer_spec.rb +++ b/spec/mailers/producer_mailer_spec.rb @@ -2,10 +2,11 @@ require 'spec_helper' require 'yaml' describe ProducerMailer do - let(:s1) { create(:supplier_enterprise, address: create(:address)) } - let(:s2) { create(:supplier_enterprise, address: create(:address)) } - let(:d1) { create(:distributor_enterprise, address: create(:address)) } - let(:d2) { create(:distributor_enterprise, address: create(:address)) } + let(:s1) { create(:supplier_enterprise) } + let(:s2) { create(:supplier_enterprise) } + let(:s3) { create(:supplier_enterprise) } + let(:d1) { create(:distributor_enterprise) } + let(:d2) { create(:distributor_enterprise) } let(:p1) { create(:product, price: 12.34, supplier: s1) } let(:p2) { create(:product, price: 23.45, supplier: s2) } let(:p3) { create(:product, price: 34.56, supplier: s1) } @@ -65,4 +66,10 @@ describe ProducerMailer do it "does not include incomplete orders" do mail.body.should_not include p3.name end + + it "sends no mail when the producer has no orders" do + expect do + ProducerMailer.order_cycle_report(s3, order_cycle).deliver + end.to change(ActionMailer::Base.deliveries, :count).by(0) + end end From 87cf3eda41b0c3fb0d2e60f902092f13fa51074a Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 29 Oct 2015 11:48:12 +1100 Subject: [PATCH 25/47] Amend 'Detailed orders breakdown' heading with missing content --- app/views/producer_mailer/order_cycle_report.text.haml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/producer_mailer/order_cycle_report.text.haml b/app/views/producer_mailer/order_cycle_report.text.haml index f6bbec8712..25eb782c1d 100644 --- a/app/views/producer_mailer/order_cycle_report.text.haml +++ b/app/views/producer_mailer/order_cycle_report.text.haml @@ -19,11 +19,12 @@ Here is a summary of the orders for your products: #{variant.sku} #{raw(variant.product.supplier.name)} #{raw(variant.product.name)} #{raw(variant.options_text)} (QTY: #{data[:quantity]}) @ #{data[:line_item].single_money} = #{data[:line_item].display_amount} \ -Detailed orders breakdown -=========================== +Details +========= +\ +For a detailed orders breakdown, please log into your account. - -Please confirm that you have got this email. +Please confirm that you have received this email. Please send me an invoice for this amount so we can send you payment. From 94e1264aefcc5b815b0931427612881d140cf1dd Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 29 Oct 2015 16:01:39 +1100 Subject: [PATCH 26/47] Add rspec-retry for inconsistently failing spec --- spec/features/admin/orders_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index 4a30c3a60c..0226529bfa 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -47,7 +47,7 @@ feature %q{ o.order_cycle.should == order_cycle end - scenario "can add a product to an existing order", js: true do + scenario "can add a product to an existing order", js: true, retry: 3 do login_to_admin_section visit '/admin/orders' From 5ffad4d343b529c0f947d33df11f1ba89543b687 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 5 Nov 2015 09:43:44 +1100 Subject: [PATCH 27/47] Fix quantity calculation --- app/mailers/producer_mailer.rb | 8 ++++++-- .../producer_mailer/order_cycle_report.text.haml | 4 ++-- spec/mailers/producer_mailer_spec.rb | 14 ++++++++++---- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index 1f021657b1..5d8ce57eec 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -41,8 +41,12 @@ class ProducerMailer < Spree::BaseMailer def aggregate_line_items(line_items) # Arrange the items in a hash to group quantities line_items.inject({}) do |lis, li| - lis[li.variant] ||= {line_item: li, quantity: 0} - lis[li.variant][:quantity] += li.quantity + if lis.key? li.variant + lis[li.variant].quantity += li.quantity + else + lis[li.variant] = li + end + lis end end diff --git a/app/views/producer_mailer/order_cycle_report.text.haml b/app/views/producer_mailer/order_cycle_report.text.haml index 25eb782c1d..67d3cde976 100644 --- a/app/views/producer_mailer/order_cycle_report.text.haml +++ b/app/views/producer_mailer/order_cycle_report.text.haml @@ -15,8 +15,8 @@ Orders summary \ Here is a summary of the orders for your products: \ -- @line_items.each_pair do |variant, data| - #{variant.sku} #{raw(variant.product.supplier.name)} #{raw(variant.product.name)} #{raw(variant.options_text)} (QTY: #{data[:quantity]}) @ #{data[:line_item].single_money} = #{data[:line_item].display_amount} +- @line_items.each_pair do |variant, line_item| + #{variant.sku} #{raw(variant.product.supplier.name)} #{raw(variant.product.name)} #{raw(variant.options_text)} (QTY: #{line_item.quantity}) @ #{line_item.single_money} = #{line_item.display_amount} \ Details diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb index e5ace458d2..2bc1d77bef 100644 --- a/spec/mailers/producer_mailer_spec.rb +++ b/spec/mailers/producer_mailer_spec.rb @@ -56,10 +56,9 @@ describe ProducerMailer do end it "contains an aggregated list of produce" do - mail.body.to_s.each_line do |line| - if line.include? p1.name - line.should include 'QTY: 2' - end + body_lines_including(mail, p1.name).each do |line| + line.should include 'QTY: 2' + line.should include '@ $10.00 = $20.00' end end @@ -72,4 +71,11 @@ describe ProducerMailer do ProducerMailer.order_cycle_report(s3, order_cycle).deliver end.to change(ActionMailer::Base.deliveries, :count).by(0) end + + + private + + def body_lines_including(mail, s) + mail.body.to_s.lines.select { |line| line.include? s } + end end From 65589d25c669d7932b062f9f1dbfefc585b2a895 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 5 Nov 2015 09:50:00 +1100 Subject: [PATCH 28/47] Display more verbose product and variant name --- app/views/producer_mailer/order_cycle_report.text.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/producer_mailer/order_cycle_report.text.haml b/app/views/producer_mailer/order_cycle_report.text.haml index 67d3cde976..1bd9099426 100644 --- a/app/views/producer_mailer/order_cycle_report.text.haml +++ b/app/views/producer_mailer/order_cycle_report.text.haml @@ -16,7 +16,7 @@ Orders summary Here is a summary of the orders for your products: \ - @line_items.each_pair do |variant, line_item| - #{variant.sku} #{raw(variant.product.supplier.name)} #{raw(variant.product.name)} #{raw(variant.options_text)} (QTY: #{line_item.quantity}) @ #{line_item.single_money} = #{line_item.display_amount} + #{variant.sku} - #{raw(variant.product.supplier.name)} - #{raw(variant.product_and_variant_name)} (QTY: #{line_item.quantity}) @ #{line_item.single_money} = #{line_item.display_amount} \ Details From aef8b9648efee295918e8b4c2a2b392313b9bc21 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Sat, 12 Sep 2015 14:42:18 +1000 Subject: [PATCH 29/47] Initial upgrade of Gemfile --- Gemfile | 4 ++-- Gemfile.lock | 18 ++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index 8be45b8651..b937a0d3f6 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ source 'https://rubygems.org' -ruby "1.9.3" +ruby "2.0.0" gem 'rails', '3.2.21' gem 'rails-i18n', '~> 3.0.0' @@ -114,7 +114,7 @@ group :test do end group :development do - gem 'pry-debugger' + gem 'pry-byebug' gem 'debugger-linecache' gem 'guard' gem 'guard-livereload' diff --git a/Gemfile.lock b/Gemfile.lock index 3dfea17147..b2ed09a169 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -171,6 +171,9 @@ GEM httparty (>= 0.6, < 1.0) multi_json (~> 1.0) builder (3.0.4) + byebug (2.7.0) + columnize (~> 0.3) + debugger-linecache (~> 1.2) cancan (1.6.8) capybara (2.2.1) mime-types (>= 1.16) @@ -196,7 +199,7 @@ GEM execjs coffee-script-source (1.3.3) colorize (0.7.7) - columnize (0.3.6) + columnize (0.9.0) comfortable_mexican_sofa (1.6.24) active_link_to (~> 1.0.0) paperclip (>= 2.3.0) @@ -230,12 +233,7 @@ GEM 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.3) debugger-linecache (1.2.0) - debugger-ruby_core_source (1.2.3) delayed_job (4.0.4) activesupport (>= 3.0, < 4.2) delayed_job_active_record (4.0.2) @@ -391,9 +389,9 @@ GEM coderay (~> 1.0.5) method_source (~> 0.8) slop (~> 3.4) - pry-debugger (0.2.2) - debugger (~> 1.3) - pry (~> 0.9.10) + pry-byebug (1.3.2) + byebug (~> 2.7) + pry (~> 0.9.12) rabl (0.7.2) activesupport (>= 2.3.14) multi_json (~> 1.0) @@ -600,7 +598,7 @@ DEPENDENCIES parallel_tests pg poltergeist - pry-debugger + pry-byebug rabl rack-livereload rack-ssl From 2277b9f5a67bf1cbf92fc1300c78f816f77a0534 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Sat, 12 Sep 2015 15:34:24 +1000 Subject: [PATCH 30/47] Changing ruby version in version manager config --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index ae6d5b9cbe..6b751b7289 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -1.9.3-p392 +2.0.0-p481 From d731d4e80375f5546a79e90933aac6ad7320e77f Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Sat, 12 Sep 2015 23:49:45 +1000 Subject: [PATCH 31/47] Making sure flash is a hash so that is can be used to initialize OpenStuct --- app/views/json/_flash.rabl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/json/_flash.rabl b/app/views/json/_flash.rabl index dce07f849a..2900b2b948 100644 --- a/app/views/json/_flash.rabl +++ b/app/views/json/_flash.rabl @@ -1,2 +1,2 @@ -object OpenStruct.new(flash) +object OpenStruct.new(flash.to_hash) attributes :info, :success, :error From b7d92786d0cd4b3733798f56071299af4809bd6a Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Sat, 19 Sep 2015 01:06:16 +1000 Subject: [PATCH 32/47] Bumping ruby version to 2.1.5 --- .ruby-version | 2 +- Gemfile | 2 +- Gemfile.lock | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.ruby-version b/.ruby-version index 6b751b7289..cd57a8b95d 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.0.0-p481 +2.1.5 diff --git a/Gemfile b/Gemfile index b937a0d3f6..f51eb993c4 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ source 'https://rubygems.org' -ruby "2.0.0" +ruby "2.1.5" gem 'rails', '3.2.21' gem 'rails-i18n', '~> 3.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index b2ed09a169..c886298743 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -251,7 +251,7 @@ GEM eventmachine (>= 0.12.9) http_parser.rb (~> 0.5.3) erubis (2.7.0) - eventmachine (1.0.3) + eventmachine (1.0.8) excon (0.25.3) execjs (2.5.2) factory_girl (3.3.0) @@ -334,7 +334,7 @@ GEM addressable (~> 2.3) letter_opener (1.0.0) launchy (>= 2.0.4) - libv8 (3.16.14.3) + libv8 (3.16.14.11) listen (2.2.0) celluloid (>= 0.15.2) rb-fsevent (>= 0.9.3) From 6666de96b29fb9e7c3de1622f47798b88ea21d6d Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 5 Nov 2015 11:24:12 +1100 Subject: [PATCH 33/47] Update ruby version used in CI --- script/ci/includes.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/ci/includes.sh b/script/ci/includes.sh index f8ccd7b4b6..323a4f4589 100644 --- a/script/ci/includes.sh +++ b/script/ci/includes.sh @@ -1,5 +1,5 @@ function load_environment { - source /var/lib/jenkins/.rvm/environments/ruby-1.9.3-p392 + source /var/lib/jenkins/.rvm/environments/ruby-2.1.5 if [ ! -f config/application.yml ]; then ln -s application.yml.example config/application.yml fi From 5db64b6f211ac33380c254d7ed5ae52ad99ec0f9 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 5 Nov 2015 12:48:22 +1100 Subject: [PATCH 34/47] Update travis config and README with new ruby version --- .travis.yml | 2 +- README.markdown | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7a7209d417..5c752d6ee4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: false cache: bundler bundler_args: --without development rvm: - - "1.9.3" + - "2.1.5" # The test cases are roughly split according to their test times. # It would be better to use https://github.com/ArturT/knapsack. diff --git a/README.markdown b/README.markdown index 15c6920be1..122e49c946 100644 --- a/README.markdown +++ b/README.markdown @@ -20,7 +20,7 @@ Below are instructions for setting up a development environment for Open Food Ne ## Dependencies * Rails 3.2.x -* Ruby 1.9.3 +* Ruby 2.1.5 * PostgreSQL database * PhantomJS (for testing) * See Gemfile for a list of gems required @@ -44,7 +44,7 @@ You can download the source with the command: For those new to Rails, the following tutorial will help get you up to speed with configuring a Rails environment: http://guides.rubyonrails.org/getting_started.html . -First, check your dependencies: Ensure that you have Ruby >= 1.9.3 installed: +First, check your dependencies: Ensure that you have Ruby 2.1.5 installed: ruby --version From 6476ce6ba9610e8db7250b7d160e665d42084aeb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Tue, 10 Nov 2015 15:05:45 +1100 Subject: [PATCH 35/47] Make spec more resilient --- spec/features/admin/bulk_order_management_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/features/admin/bulk_order_management_spec.rb b/spec/features/admin/bulk_order_management_spec.rb index 5bcca783bd..271d3bd2f2 100644 --- a/spec/features/admin/bulk_order_management_spec.rb +++ b/spec/features/admin/bulk_order_management_spec.rb @@ -294,7 +294,6 @@ feature %q{ expect(page).to have_selector "tr#li_#{li1.id}" expect(page).to have_selector "tr#li_#{li2.id}" select2_select oc1.name, from: "order_cycle_filter" - expect(page).to have_selector "#loading img.spinner" expect(page).to_not have_selector "#loading img.spinner" expect(page).to have_selector "tr#li_#{li1.id}" expect(page).to_not have_selector "tr#li_#{li2.id}" From d794981ecfb66616cd5de799e2a80999148a30bc Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 10:44:33 +1100 Subject: [PATCH 36/47] Add form field to set tax when creating adjustment on order. Display tax included in adjustments on order interface. --- app/models/spree/adjustment_decorator.rb | 4 ++++ .../add_tax_to_body.html.haml.deface | 9 +++++++++ .../add_tax_to_head.html.haml.deface | 8 ++++++++ .../_form/add_tax_rate.html.haml.deface | 6 ++++++ .../spree/admin/adjustments/_new_form.html.haml | 17 +++++++++++++++++ config/locales/en.yml | 1 + 6 files changed, 45 insertions(+) create mode 100644 app/overrides/spree/admin/adjustments/_adjustments_table/add_tax_to_body.html.haml.deface create mode 100644 app/overrides/spree/admin/adjustments/_adjustments_table/add_tax_to_head.html.haml.deface create mode 100644 app/overrides/spree/admin/adjustments/_form/add_tax_rate.html.haml.deface create mode 100644 app/views/spree/admin/adjustments/_new_form.html.haml diff --git a/app/models/spree/adjustment_decorator.rb b/app/models/spree/adjustment_decorator.rb index 5f3847e218..b179fe3036 100644 --- a/app/models/spree/adjustment_decorator.rb +++ b/app/models/spree/adjustment_decorator.rb @@ -24,6 +24,10 @@ module Spree update_attributes! included_tax: tax.round(2) end + def display_included_tax + Spree::Money.new(included_tax, { :currency => currency }) + end + def has_tax? included_tax > 0 end diff --git a/app/overrides/spree/admin/adjustments/_adjustments_table/add_tax_to_body.html.haml.deface b/app/overrides/spree/admin/adjustments/_adjustments_table/add_tax_to_body.html.haml.deface new file mode 100644 index 0000000000..398d99eaf6 --- /dev/null +++ b/app/overrides/spree/admin/adjustments/_adjustments_table/add_tax_to_body.html.haml.deface @@ -0,0 +1,9 @@ +/ replace_contents "[data-hook='adjustment_row']" + +%td.align-center.created_at= pretty_time(adjustment.created_at) +%td.align-center.label= adjustment.label +%td.align-center.amount= adjustment.display_amount.to_html +%td.align-center.included-tax= adjustment.display_included_tax.to_html +%td.actions + = link_to_edit adjustment, no_text: true + = link_to_delete adjustment, no_text: true \ No newline at end of file diff --git a/app/overrides/spree/admin/adjustments/_adjustments_table/add_tax_to_head.html.haml.deface b/app/overrides/spree/admin/adjustments/_adjustments_table/add_tax_to_head.html.haml.deface new file mode 100644 index 0000000000..6da264865a --- /dev/null +++ b/app/overrides/spree/admin/adjustments/_adjustments_table/add_tax_to_head.html.haml.deface @@ -0,0 +1,8 @@ +/ replace_contents "[data-hook='adjustmment_head']" + +%tr + %th= "#{t('spree.date')}/#{t('spree.time')}" + %th= t(:description) + %th= t(:amount) + %th= t(:included_tax) + %th.actions diff --git a/app/overrides/spree/admin/adjustments/_form/add_tax_rate.html.haml.deface b/app/overrides/spree/admin/adjustments/_form/add_tax_rate.html.haml.deface new file mode 100644 index 0000000000..a37acc1030 --- /dev/null +++ b/app/overrides/spree/admin/adjustments/_form/add_tax_rate.html.haml.deface @@ -0,0 +1,6 @@ +/ replace_contents "[data-hook='admin_adjustment_form_fields']" + +- if @adjustment.new_record? + = render 'new_form', f: f +- else + = render 'edit_form', f: f diff --git a/app/views/spree/admin/adjustments/_new_form.html.haml b/app/views/spree/admin/adjustments/_new_form.html.haml new file mode 100644 index 0000000000..a3981fca8a --- /dev/null +++ b/app/views/spree/admin/adjustments/_new_form.html.haml @@ -0,0 +1,17 @@ +.row + .alpha.three.columns + = f.field_container :amount do + = f.label :amount, raw(t(:amount) + content_tag(:span, " *", :class => "required")) + = text_field :adjustment, :amount, :class => 'fullwidth' + = f.error_message_on :amount + .omega.three.columns + = f.field_container :tax_rate_id do + = f.label :tax_rate_id, t(:tax) + = select_tag :tax_rate_id, options_from_collection_for_select(Spree::TaxRate.all, :id, :name), prompt: t(:none), class: 'fullwidth' + = f.error_message_on :tax_rate_id +.row + .alpha.omega.twelve.columns + = f.field_container :label do + = f.label :label, raw(t(:description) + content_tag(:span, " *", :class => "required")) + = text_field :adjustment, :label, :class => 'fullwidth' + = f.error_message_on :label diff --git a/config/locales/en.yml b/config/locales/en.yml index e6ede20009..600b21321f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -38,3 +38,4 @@ en: footer_about_url: "About URL" footer_tos_url: "Terms of Service URL" invoice: "Invoice" + included_tax: "Included tax" \ No newline at end of file From 46a9304ae1c8a2c74c6c2f662d0e93b7affdc250 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 10:59:29 +1100 Subject: [PATCH 37/47] Extract compute_tax from EnterpriseFeeApplicator to Spree::TaxRate model --- app/models/spree/tax_rate_decorator.rb | 67 +++++++++++++++---- .../enterprise_fee_applicator.rb | 37 +--------- .../enterprise_fee_applicator_spec.rb | 29 -------- spec/models/spree/tax_rate_spec.rb | 28 ++++++++ 4 files changed, 83 insertions(+), 78 deletions(-) diff --git a/app/models/spree/tax_rate_decorator.rb b/app/models/spree/tax_rate_decorator.rb index 42eae86b8c..80bcc450c2 100644 --- a/app/models/spree/tax_rate_decorator.rb +++ b/app/models/spree/tax_rate_decorator.rb @@ -1,20 +1,61 @@ -Spree::TaxRate.class_eval do - class << self - def match_with_sales_tax_registration(order) - return [] if order.distributor && !order.distributor.charges_sales_tax - match_without_sales_tax_registration(order) +module Spree + TaxRate.class_eval do + class << self + def match_with_sales_tax_registration(order) + return [] if order.distributor && !order.distributor.charges_sales_tax + match_without_sales_tax_registration(order) + end + alias_method_chain :match, :sales_tax_registration end - alias_method_chain :match, :sales_tax_registration - end - def adjust_with_included_tax(order) - adjust_without_included_tax(order) + def adjust_with_included_tax(order) + adjust_without_included_tax(order) - order.reload - (order.adjustments.tax + order.price_adjustments).each do |a| - a.set_absolute_included_tax! a.amount + order.reload + (order.adjustments.tax + order.price_adjustments).each do |a| + a.set_absolute_included_tax! a.amount + end + end + alias_method_chain :adjust, :included_tax + + + # Manually apply a TaxRate to a particular amount. TaxRates normally compute against + # LineItems or Orders, so we mock out a line item here to fit the interface + # that our calculator (usually DefaultTax) expects. + def compute_tax(amount) + product = OpenStruct.new tax_category: tax_category + line_item = LineItem.new quantity: 1 + line_item.define_singleton_method(:product) { product } + line_item.define_singleton_method(:price) { amount } + + # Tax on adjustments (represented by the included_tax field) is always inclusive of + # tax. However, there's nothing to stop an admin from setting one up with a tax rate + # that's marked as not inclusive of tax, and that would result in the DefaultTax + # calculator generating a slightly incorrect value. Therefore, we treat the tax + # rate as inclusive of tax for the calculations below, regardless of its original + # setting. + with_tax_included_in_price do + calculator.compute line_item + end + end + + + private + + def with_tax_included_in_price + old_included_in_price = self.included_in_price + + self.included_in_price = true + calculator.calculable.included_in_price = true + + result = yield + + # TODO: ensure + self.included_in_price = old_included_in_price + calculator.calculable.included_in_price = old_included_in_price + + result end end - alias_method_chain :adjust, :included_tax end diff --git a/lib/open_food_network/enterprise_fee_applicator.rb b/lib/open_food_network/enterprise_fee_applicator.rb index 070cb4a91c..4962bc148e 100644 --- a/lib/open_food_network/enterprise_fee_applicator.rb +++ b/lib/open_food_network/enterprise_fee_applicator.rb @@ -35,43 +35,8 @@ module OpenFoodNetwork tax_rates = enterprise_fee.tax_category ? enterprise_fee.tax_category.tax_rates.match(order) : [] tax_rates.sum do |rate| - compute_tax rate, adjustment.amount + rate.compute_tax adjustment.amount end end - - # Apply a TaxRate to a particular amount. TaxRates normally compute against - # LineItems or Orders, so we mock out a line item here to fit the interface - # that our calculator (usually DefaultTax) expects. - def compute_tax(tax_rate, amount) - product = OpenStruct.new tax_category: tax_rate.tax_category - line_item = Spree::LineItem.new quantity: 1 - line_item.define_singleton_method(:product) { product } - line_item.define_singleton_method(:price) { amount } - - # The enterprise fee adjustments for which we're calculating tax are always inclusive of - # tax. However, there's nothing to stop an admin from setting one up with a tax rate - # that's marked as not inclusive of tax, and that would result in the DefaultTax - # calculator generating a slightly incorrect value. Therefore, we treat the tax - # rate as inclusive of tax for the calculations below, regardless of its original - # setting. - with_tax_included_in_price(tax_rate) do - tax_rate.calculator.compute line_item - end - end - - def with_tax_included_in_price(tax_rate) - old_included_in_price = tax_rate.included_in_price - - tax_rate.included_in_price = true - tax_rate.calculator.calculable.included_in_price = true - - result = yield - - tax_rate.included_in_price = old_included_in_price - tax_rate.calculator.calculable.included_in_price = old_included_in_price - - result - end end end - diff --git a/spec/lib/open_food_network/enterprise_fee_applicator_spec.rb b/spec/lib/open_food_network/enterprise_fee_applicator_spec.rb index 6703f844ab..9ad1d222b3 100644 --- a/spec/lib/open_food_network/enterprise_fee_applicator_spec.rb +++ b/spec/lib/open_food_network/enterprise_fee_applicator_spec.rb @@ -65,33 +65,4 @@ module OpenFoodNetwork efa.send(:order_adjustment_label).should == "Whole order - packing fee by distributor Ballantyne" end end - - describe "ensuring that tax rate is marked as tax included_in_price" do - let(:efa) { EnterpriseFeeApplicator.new nil, nil, nil } - let(:tax_rate) { create(:tax_rate, included_in_price: false, calculator: Spree::Calculator::DefaultTax.new) } - - it "sets included_in_price to true" do - efa.send(:with_tax_included_in_price, tax_rate) do - tax_rate.included_in_price.should be_true - end - end - - it "sets the included_in_price value accessible to the calculator to true" do - efa.send(:with_tax_included_in_price, tax_rate) do - tax_rate.calculator.calculable.included_in_price.should be_true - end - end - - it "passes through the return value of the block" do - efa.send(:with_tax_included_in_price, tax_rate) do - 'asdf' - end.should == 'asdf' - end - - it "restores both values to their original afterwards" do - efa.send(:with_tax_included_in_price, tax_rate) {} - tax_rate.included_in_price.should be_false - tax_rate.calculator.calculable.included_in_price.should be_false - end - end end diff --git a/spec/models/spree/tax_rate_spec.rb b/spec/models/spree/tax_rate_spec.rb index 25aad986a0..c10f00ac44 100644 --- a/spec/models/spree/tax_rate_spec.rb +++ b/spec/models/spree/tax_rate_spec.rb @@ -29,5 +29,33 @@ module Spree end end end + + describe "ensuring that tax rate is marked as tax included_in_price" do + let(:tax_rate) { create(:tax_rate, included_in_price: false, calculator: Spree::Calculator::DefaultTax.new) } + + it "sets included_in_price to true" do + tax_rate.send(:with_tax_included_in_price) do + tax_rate.included_in_price.should be_true + end + end + + it "sets the included_in_price value accessible to the calculator to true" do + tax_rate.send(:with_tax_included_in_price) do + tax_rate.calculator.calculable.included_in_price.should be_true + end + end + + it "passes through the return value of the block" do + tax_rate.send(:with_tax_included_in_price) do + 'asdf' + end.should == 'asdf' + end + + it "restores both values to their original afterwards" do + tax_rate.send(:with_tax_included_in_price) {} + tax_rate.included_in_price.should be_false + tax_rate.calculator.calculable.included_in_price.should be_false + end + end end end From 83c0093665a7636851a0122e8a4f4eb8716ef4ba Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 11:18:55 +1100 Subject: [PATCH 38/47] Admin can include tax when creating an adjustment --- .../admin/adjustments_controller_decorator.rb | 17 ++++++++++ .../admin/adjustments_controller_spec.rb | 34 +++++++++++++++++++ spec/features/admin/orders_spec.rb | 24 +++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 app/controllers/spree/admin/adjustments_controller_decorator.rb create mode 100644 spec/controllers/spree/admin/adjustments_controller_spec.rb diff --git a/app/controllers/spree/admin/adjustments_controller_decorator.rb b/app/controllers/spree/admin/adjustments_controller_decorator.rb new file mode 100644 index 0000000000..23cce4a623 --- /dev/null +++ b/app/controllers/spree/admin/adjustments_controller_decorator.rb @@ -0,0 +1,17 @@ +module Spree + module Admin + AdjustmentsController.class_eval do + before_filter :set_included_tax, only: :create + + private + + def set_included_tax + if params[:tax_rate_id].present? + tax_rate = TaxRate.find params[:tax_rate_id] + amount = params[:adjustment][:amount].to_f + params[:adjustment][:included_tax] = tax_rate.compute_tax amount + end + end + end + end +end diff --git a/spec/controllers/spree/admin/adjustments_controller_spec.rb b/spec/controllers/spree/admin/adjustments_controller_spec.rb new file mode 100644 index 0000000000..bc0b4644ff --- /dev/null +++ b/spec/controllers/spree/admin/adjustments_controller_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +module Spree + describe Admin::AdjustmentsController do + include AuthenticationWorkflow + + before { login_as_admin } + + describe "setting included tax when creating an adjustment" do + let(:order) { create(:order) } + let(:tax_rate) { create(:tax_rate, amount: 0.1, calculator: Spree::Calculator::DefaultTax.new) } + + it "sets included tax to zero when no tax rate is specified" do + spree_put :create, {order_id: order.number, adjustment: {label: 'Testing included tax', amount: '110'}, tax_rate_id: ''} + response.should redirect_to spree.admin_order_adjustments_path(order) + + a = Adjustment.last + a.label.should == 'Testing included tax' + a.amount.should == 110 + a.included_tax.should == 0 + end + + it "calculates included tax when a tax rate is provided" do + spree_put :create, {order_id: order.number, adjustment: {label: 'Testing included tax', amount: '110'}, tax_rate_id: tax_rate.id.to_s} + response.should redirect_to spree.admin_order_adjustments_path(order) + + a = Adjustment.last + a.label.should == 'Testing included tax' + a.amount.should == 110 + a.included_tax.should == 10 + end + end + end +end diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index 4a30c3a60c..2a3464abf9 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -106,6 +106,30 @@ feature %q{ current_path.should == spree.admin_orders_path end + scenario "adding taxed adjustments to an order" do + # Given a tax rate + create(:tax_rate, name: 'GST', calculator: build(:calculator, preferred_amount: 10)) + + # When I go to the adjustments page for the order + login_to_admin_section + visit spree.admin_orders_path + page.find('td.actions a.icon-edit').click + click_link 'Adjustments' + + # And I create a new adjustment with tax + click_link 'New Adjustment' + fill_in 'adjustment_amount', with: 110 + fill_in 'adjustment_label', with: 'Late fee' + select 'GST', from: 'tax_rate_id' + click_button 'Continue' + + # Then I should see the adjustment, with the correct tax + page.should have_selector 'td.label', text: 'Late fee' + page.should have_selector 'td.amount', text: '110' + page.should have_selector 'td.included-tax', text: '10' + end + + context "as an enterprise manager" do let(:coordinator1) { create(:distributor_enterprise) } let(:coordinator2) { create(:distributor_enterprise) } From 85e45fa5589b39ab2f7f9f1f3841e36d6877d177 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 11:25:15 +1100 Subject: [PATCH 39/47] Use select2 --- app/views/spree/admin/adjustments/_new_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/adjustments/_new_form.html.haml b/app/views/spree/admin/adjustments/_new_form.html.haml index a3981fca8a..b955fedb6d 100644 --- a/app/views/spree/admin/adjustments/_new_form.html.haml +++ b/app/views/spree/admin/adjustments/_new_form.html.haml @@ -7,7 +7,7 @@ .omega.three.columns = f.field_container :tax_rate_id do = f.label :tax_rate_id, t(:tax) - = select_tag :tax_rate_id, options_from_collection_for_select(Spree::TaxRate.all, :id, :name), prompt: t(:none), class: 'fullwidth' + = select_tag :tax_rate_id, options_from_collection_for_select(Spree::TaxRate.all, :id, :name), prompt: t(:none), class: 'select2 fullwidth' = f.error_message_on :tax_rate_id .row .alpha.omega.twelve.columns From 727ecae62b8b8299c151301d4f4b47cb21749b47 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 11:56:16 +1100 Subject: [PATCH 40/47] Admin can modify a taxed adjustment on an order --- .../admin/adjustments_controller_decorator.rb | 8 +++++ .../admin/adjustments/_edit_form.html.haml | 25 ++++++++++++++ config/locales/en.yml | 3 +- spec/features/admin/orders_spec.rb | 33 +++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 app/views/spree/admin/adjustments/_edit_form.html.haml diff --git a/app/controllers/spree/admin/adjustments_controller_decorator.rb b/app/controllers/spree/admin/adjustments_controller_decorator.rb index 23cce4a623..1414a330a2 100644 --- a/app/controllers/spree/admin/adjustments_controller_decorator.rb +++ b/app/controllers/spree/admin/adjustments_controller_decorator.rb @@ -2,9 +2,17 @@ module Spree module Admin AdjustmentsController.class_eval do before_filter :set_included_tax, only: :create + before_filter :set_default_tax_rate, only: :edit private + def set_default_tax_rate + if @adjustment.included_tax > 0 && TaxRate.count == 1 + @tax_rate_id = TaxRate.first.id + end + end + + def set_included_tax if params[:tax_rate_id].present? tax_rate = TaxRate.find params[:tax_rate_id] diff --git a/app/views/spree/admin/adjustments/_edit_form.html.haml b/app/views/spree/admin/adjustments/_edit_form.html.haml new file mode 100644 index 0000000000..98e02ce555 --- /dev/null +++ b/app/views/spree/admin/adjustments/_edit_form.html.haml @@ -0,0 +1,25 @@ +.row + .alpha.three.columns + = f.field_container :amount do + = f.label :amount, raw(t(:amount) + content_tag(:span, " *", :class => "required")) + = text_field :adjustment, :amount, :class => 'fullwidth' + = f.error_message_on :amount + + .three.columns + = f.field_container :included_tax do + = f.label :included_tax, t(:included_tax) + = text_field :adjustment, :included_tax, disabled: true, class: 'fullwidth' + = f.error_message_on :included_tax + + .omega.three.columns + = f.field_container :tax_rate_id do + = f.label :tax_rate_id, t(:tax) + = select_tag :tax_rate_id, options_from_collection_for_select(Spree::TaxRate.all, :id, :name, @tax_rate_id), prompt: t(:remove_tax), class: 'select2 fullwidth' + = f.error_message_on :tax_rate_id + +.row + .alpha.omega.twelve.columns + = f.field_container :label do + = f.label :label, raw(t(:description) + content_tag(:span, " *", :class => "required")) + = text_field :adjustment, :label, :class => 'fullwidth' + = f.error_message_on :label diff --git a/config/locales/en.yml b/config/locales/en.yml index 600b21321f..08dde26cd8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -38,4 +38,5 @@ en: footer_about_url: "About URL" footer_tos_url: "Terms of Service URL" invoice: "Invoice" - included_tax: "Included tax" \ No newline at end of file + included_tax: "Included tax" + remove_tax: "Remove tax" diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index 2a3464abf9..59fc205690 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -129,6 +129,39 @@ feature %q{ page.should have_selector 'td.included-tax', text: '10' end + scenario "modifying taxed adjustments on an order" do + # Given a tax rate and a taxed adjustment + tax_rate = create(:tax_rate, name: 'GST', calculator: build(:calculator, preferred_amount: 10)) + adjustment = create(:adjustment, adjustable: @order, amount: 110, included_tax: 10) + + # When I go to the adjustments page for the order + login_to_admin_section + visit spree.admin_orders_path + page.find('td.actions a.icon-edit').click + click_link 'Adjustments' + page.find('td.actions a.icon-edit').click + + # Then I should see the uneditable included tax and our tax rate as the default + page.should have_field :adjustment_included_tax, with: '10.00', disabled: true + page.should have_select :tax_rate_id, selected: 'GST' + + # When I edit the adjustment, removing the tax + select 'Remove tax', from: :tax_rate_id + click_button 'Continue' + + # Then the adjustment tax should be cleared + page.should have_selector 'td.amount', text: '110' + page.should have_selector 'td.included-tax', text: '0' + end + + scenario "modifying an untaxed adjustment on an order" do + # Given a tax rate and an untaxed adjustment + # When I go to the adjustments page for the order + # Then I should see 'Remove tax' as the default tax rate + # When I edit the adjustment, setting a tax rate + # Then the adjustment tax should be recalculated + end + context "as an enterprise manager" do let(:coordinator1) { create(:distributor_enterprise) } From 81a6e07d5c1cbeb212c1faa8c5053f11023fd7ce Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 12:25:55 +1100 Subject: [PATCH 41/47] Admin can remove tax on an adjustment --- .../admin/adjustments_controller_decorator.rb | 5 +- .../admin/adjustments_controller_spec.rb | 56 ++++++++++++++----- spec/features/admin/orders_spec.rb | 19 ++++++- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/app/controllers/spree/admin/adjustments_controller_decorator.rb b/app/controllers/spree/admin/adjustments_controller_decorator.rb index 1414a330a2..e6a10d6eac 100644 --- a/app/controllers/spree/admin/adjustments_controller_decorator.rb +++ b/app/controllers/spree/admin/adjustments_controller_decorator.rb @@ -1,7 +1,7 @@ module Spree module Admin AdjustmentsController.class_eval do - before_filter :set_included_tax, only: :create + before_filter :set_included_tax, only: [:create, :update] before_filter :set_default_tax_rate, only: :edit private @@ -18,6 +18,9 @@ module Spree tax_rate = TaxRate.find params[:tax_rate_id] amount = params[:adjustment][:amount].to_f params[:adjustment][:included_tax] = tax_rate.compute_tax amount + + else + params[:adjustment][:included_tax] = 0 end end end diff --git a/spec/controllers/spree/admin/adjustments_controller_spec.rb b/spec/controllers/spree/admin/adjustments_controller_spec.rb index bc0b4644ff..bb20fb792b 100644 --- a/spec/controllers/spree/admin/adjustments_controller_spec.rb +++ b/spec/controllers/spree/admin/adjustments_controller_spec.rb @@ -6,28 +6,54 @@ module Spree before { login_as_admin } - describe "setting included tax when creating an adjustment" do + describe "setting included tax" do let(:order) { create(:order) } let(:tax_rate) { create(:tax_rate, amount: 0.1, calculator: Spree::Calculator::DefaultTax.new) } - it "sets included tax to zero when no tax rate is specified" do - spree_put :create, {order_id: order.number, adjustment: {label: 'Testing included tax', amount: '110'}, tax_rate_id: ''} - response.should redirect_to spree.admin_order_adjustments_path(order) + describe "creating an adjustment" do + it "sets included tax to zero when no tax rate is specified" do + spree_post :create, {order_id: order.number, adjustment: {label: 'Testing included tax', amount: '110'}, tax_rate_id: ''} + response.should redirect_to spree.admin_order_adjustments_path(order) - a = Adjustment.last - a.label.should == 'Testing included tax' - a.amount.should == 110 - a.included_tax.should == 0 + a = Adjustment.last + a.label.should == 'Testing included tax' + a.amount.should == 110 + a.included_tax.should == 0 + end + + it "calculates included tax when a tax rate is provided" do + spree_post :create, {order_id: order.number, adjustment: {label: 'Testing included tax', amount: '110'}, tax_rate_id: tax_rate.id.to_s} + response.should redirect_to spree.admin_order_adjustments_path(order) + + a = Adjustment.last + a.label.should == 'Testing included tax' + a.amount.should == 110 + a.included_tax.should == 10 + end end - it "calculates included tax when a tax rate is provided" do - spree_put :create, {order_id: order.number, adjustment: {label: 'Testing included tax', amount: '110'}, tax_rate_id: tax_rate.id.to_s} - response.should redirect_to spree.admin_order_adjustments_path(order) + describe "updating an adjustment" do + let(:adjustment) { create(:adjustment, adjustable: order, amount: 1100, included_tax: 100) } - a = Adjustment.last - a.label.should == 'Testing included tax' - a.amount.should == 110 - a.included_tax.should == 10 + it "sets included tax to zero when no tax rate is specified" do + spree_put :update, {order_id: order.number, id: adjustment.id, adjustment: {label: 'Testing included tax', amount: '110'}, tax_rate_id: ''} + response.should redirect_to spree.admin_order_adjustments_path(order) + + a = Adjustment.last + a.label.should == 'Testing included tax' + a.amount.should == 110 + a.included_tax.should == 0 + end + + it "calculates included tax when a tax rate is provided" do + spree_put :update, {order_id: order.number, id: adjustment.id, adjustment: {label: 'Testing included tax', amount: '110'}, tax_rate_id: tax_rate.id.to_s} + response.should redirect_to spree.admin_order_adjustments_path(order) + + a = Adjustment.last + a.label.should == 'Testing included tax' + a.amount.should == 110 + a.included_tax.should == 10 + end end end end diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index 59fc205690..f89f8d6ac5 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -156,10 +156,27 @@ feature %q{ scenario "modifying an untaxed adjustment on an order" do # Given a tax rate and an untaxed adjustment + tax_rate = create(:tax_rate, name: 'GST', calculator: build(:calculator, preferred_amount: 10)) + adjustment = create(:adjustment, adjustable: @order, amount: 110, included_tax: 0) + # When I go to the adjustments page for the order - # Then I should see 'Remove tax' as the default tax rate + login_to_admin_section + visit spree.admin_orders_path + page.find('td.actions a.icon-edit').click + click_link 'Adjustments' + page.find('td.actions a.icon-edit').click + + # Then I should see the uneditable included tax and 'Remove tax' as the default tax rate + page.should have_field :adjustment_included_tax, with: '0.00', disabled: true + page.should have_select :tax_rate_id, selected: [] + # When I edit the adjustment, setting a tax rate + select 'GST', from: :tax_rate_id + click_button 'Continue' + # Then the adjustment tax should be recalculated + page.should have_selector 'td.amount', text: '110' + page.should have_selector 'td.included-tax', text: '10' end From 3e7a12cca169ab3ba2015a55d26e829f3d812698 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 12:26:19 +1100 Subject: [PATCH 42/47] Rename spec support method for faster tab completion on save_and_open_page --- spec/support/html_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/support/html_helper.rb b/spec/support/html_helper.rb index 54c6ffe1f1..ffa261fc39 100644 --- a/spec/support/html_helper.rb +++ b/spec/support/html_helper.rb @@ -1,6 +1,6 @@ module OpenFoodNetwork module HtmlHelper - def save_and_open(html) + def html_save_and_open(html) require "launchy" file = Tempfile.new('html') file.write html From 5a29311137f949d478823e267c6edd02e9a74214 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 14:51:15 +1100 Subject: [PATCH 43/47] Choose a more sensible default tax rate: one that calculates to the same amount as the current adjustment tax --- .../admin/adjustments_controller_decorator.rb | 20 +++++++++++++++++-- spec/features/admin/orders_spec.rb | 4 ++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/controllers/spree/admin/adjustments_controller_decorator.rb b/app/controllers/spree/admin/adjustments_controller_decorator.rb index e6a10d6eac..12c9ae2c60 100644 --- a/app/controllers/spree/admin/adjustments_controller_decorator.rb +++ b/app/controllers/spree/admin/adjustments_controller_decorator.rb @@ -4,11 +4,27 @@ module Spree before_filter :set_included_tax, only: [:create, :update] before_filter :set_default_tax_rate, only: :edit + private + # Choose a default tax rate to show on the edit form. The adjustment stores its included + # tax in dollars, but doesn't store the source of the tax (ie. TaxRate that generated it). + # We guess which tax rate here, choosing: + # 1. A tax rate that will compute to the same amount as the existing tax + # 2. If that's not present, the first tax rate that's valid for the current order + # When we have to go with 2, we show an error message to ask the admin to check that the + # correct tax is being applied. def set_default_tax_rate - if @adjustment.included_tax > 0 && TaxRate.count == 1 - @tax_rate_id = TaxRate.first.id + if @adjustment.included_tax > 0 + trs = TaxRate.match(@order) + tr_yielding_matching_tax = trs.select { |tr| tr.compute_tax(@adjustment.amount) == @adjustment.included_tax }.first.andand.id + tr_valid_for_order = TaxRate.match(@order).first.andand.id + + @tax_rate_id = tr_yielding_matching_tax || tr_valid_for_order + + if tr_yielding_matching_tax.nil? + @adjustment.errors.add :tax_rate_id, "^Please check that the tax rate for this adjustment is correct." + end end end diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index f89f8d6ac5..a41c5b9dce 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -10,7 +10,7 @@ feature %q{ background do @user = create(:user) @product = create(:simple_product) - @distributor = create(:distributor_enterprise) + @distributor = create(:distributor_enterprise, charges_sales_tax: true) @order_cycle = create(:simple_order_cycle, distributors: [@distributor], variants: [@product.variants.first]) @order = create(:order_with_totals_and_distribution, user: @user, distributor: @distributor, order_cycle: @order_cycle, state: 'complete', payment_state: 'balance_due') @@ -131,7 +131,7 @@ feature %q{ scenario "modifying taxed adjustments on an order" do # Given a tax rate and a taxed adjustment - tax_rate = create(:tax_rate, name: 'GST', calculator: build(:calculator, preferred_amount: 10)) + tax_rate = create(:tax_rate, name: 'GST', calculator: build(:calculator, preferred_amount: 10), zone: create(:zone_with_member)) adjustment = create(:adjustment, adjustable: @order, amount: 110, included_tax: 10) # When I go to the adjustments page for the order From a32321df6803e485b290469fc5e42099e9992e5c Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 14:54:15 +1100 Subject: [PATCH 44/47] Clarify label --- app/views/spree/admin/adjustments/_edit_form.html.haml | 2 +- app/views/spree/admin/adjustments/_new_form.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/spree/admin/adjustments/_edit_form.html.haml b/app/views/spree/admin/adjustments/_edit_form.html.haml index 98e02ce555..27d2669a4f 100644 --- a/app/views/spree/admin/adjustments/_edit_form.html.haml +++ b/app/views/spree/admin/adjustments/_edit_form.html.haml @@ -13,7 +13,7 @@ .omega.three.columns = f.field_container :tax_rate_id do - = f.label :tax_rate_id, t(:tax) + = f.label :tax_rate_id, t(:tax_rate) = select_tag :tax_rate_id, options_from_collection_for_select(Spree::TaxRate.all, :id, :name, @tax_rate_id), prompt: t(:remove_tax), class: 'select2 fullwidth' = f.error_message_on :tax_rate_id diff --git a/app/views/spree/admin/adjustments/_new_form.html.haml b/app/views/spree/admin/adjustments/_new_form.html.haml index b955fedb6d..cafce77c5f 100644 --- a/app/views/spree/admin/adjustments/_new_form.html.haml +++ b/app/views/spree/admin/adjustments/_new_form.html.haml @@ -6,7 +6,7 @@ = f.error_message_on :amount .omega.three.columns = f.field_container :tax_rate_id do - = f.label :tax_rate_id, t(:tax) + = f.label :tax_rate_id, t(:tax_rate) = select_tag :tax_rate_id, options_from_collection_for_select(Spree::TaxRate.all, :id, :name), prompt: t(:none), class: 'select2 fullwidth' = f.error_message_on :tax_rate_id .row From 8e1bade35541477c43c15fe03a68b1d3acc2d8f5 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 15:28:03 +1100 Subject: [PATCH 45/47] Move adjustment specs to their own spec file --- spec/features/admin/adjustments_spec.rb | 89 +++++++++++++++++++++++++ spec/features/admin/orders_spec.rb | 77 +-------------------- 2 files changed, 91 insertions(+), 75 deletions(-) create mode 100644 spec/features/admin/adjustments_spec.rb diff --git a/spec/features/admin/adjustments_spec.rb b/spec/features/admin/adjustments_spec.rb new file mode 100644 index 0000000000..b9a6ee3465 --- /dev/null +++ b/spec/features/admin/adjustments_spec.rb @@ -0,0 +1,89 @@ +require "spec_helper" + +feature %q{ + As an administrator + I want to manage adjustments on orders +} do + include AuthenticationWorkflow + include WebHelper + + let!(:user) { create(:user) } + let!(:distributor) { create(:distributor_enterprise, charges_sales_tax: true) } + let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor]) } + + let!(:order) { create(:order_with_totals_and_distribution, user: user, distributor: distributor, order_cycle: order_cycle, state: 'complete', payment_state: 'balance_due') } + let!(:tax_rate) { create(:tax_rate, name: 'GST', calculator: build(:calculator, preferred_amount: 10), zone: create(:zone_with_member)) } + + before do + order.finalize! + create(:check_payment, order: order, amount: order.total) + end + + scenario "adding taxed adjustments to an order" do + # When I go to the adjustments page for the order + login_to_admin_section + visit spree.admin_orders_path + page.find('td.actions a.icon-edit').click + click_link 'Adjustments' + + # And I create a new adjustment with tax + click_link 'New Adjustment' + fill_in 'adjustment_amount', with: 110 + fill_in 'adjustment_label', with: 'Late fee' + select 'GST', from: 'tax_rate_id' + click_button 'Continue' + + # Then I should see the adjustment, with the correct tax + page.should have_selector 'td.label', text: 'Late fee' + page.should have_selector 'td.amount', text: '110' + page.should have_selector 'td.included-tax', text: '10' + end + + scenario "modifying taxed adjustments on an order" do + # Given a taxed adjustment + adjustment = create(:adjustment, adjustable: order, amount: 110, included_tax: 10) + + # When I go to the adjustments page for the order + login_to_admin_section + visit spree.admin_orders_path + page.find('td.actions a.icon-edit').click + click_link 'Adjustments' + page.find('td.actions a.icon-edit').click + + # Then I should see the uneditable included tax and our tax rate as the default + page.should have_field :adjustment_included_tax, with: '10.00', disabled: true + page.should have_select :tax_rate_id, selected: 'GST' + + # When I edit the adjustment, removing the tax + select 'Remove tax', from: :tax_rate_id + click_button 'Continue' + + # Then the adjustment tax should be cleared + page.should have_selector 'td.amount', text: '110' + page.should have_selector 'td.included-tax', text: '0' + end + + scenario "modifying an untaxed adjustment on an order" do + # Given an untaxed adjustment + adjustment = create(:adjustment, adjustable: order, amount: 110, included_tax: 0) + + # When I go to the adjustments page for the order + login_to_admin_section + visit spree.admin_orders_path + page.find('td.actions a.icon-edit').click + click_link 'Adjustments' + page.find('td.actions a.icon-edit').click + + # Then I should see the uneditable included tax and 'Remove tax' as the default tax rate + page.should have_field :adjustment_included_tax, with: '0.00', disabled: true + page.should have_select :tax_rate_id, selected: [] + + # When I edit the adjustment, setting a tax rate + select 'GST', from: :tax_rate_id + click_button 'Continue' + + # Then the adjustment tax should be recalculated + page.should have_selector 'td.amount', text: '110' + page.should have_selector 'td.included-tax', text: '10' + end +end diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index a41c5b9dce..36677a6d4f 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -1,8 +1,8 @@ require "spec_helper" feature %q{ - As a payment administrator - I want to capture multiple payments quickly from the one page + As an administrator + I want to manage orders } do include AuthenticationWorkflow include WebHelper @@ -106,79 +106,6 @@ feature %q{ current_path.should == spree.admin_orders_path end - scenario "adding taxed adjustments to an order" do - # Given a tax rate - create(:tax_rate, name: 'GST', calculator: build(:calculator, preferred_amount: 10)) - - # When I go to the adjustments page for the order - login_to_admin_section - visit spree.admin_orders_path - page.find('td.actions a.icon-edit').click - click_link 'Adjustments' - - # And I create a new adjustment with tax - click_link 'New Adjustment' - fill_in 'adjustment_amount', with: 110 - fill_in 'adjustment_label', with: 'Late fee' - select 'GST', from: 'tax_rate_id' - click_button 'Continue' - - # Then I should see the adjustment, with the correct tax - page.should have_selector 'td.label', text: 'Late fee' - page.should have_selector 'td.amount', text: '110' - page.should have_selector 'td.included-tax', text: '10' - end - - scenario "modifying taxed adjustments on an order" do - # Given a tax rate and a taxed adjustment - tax_rate = create(:tax_rate, name: 'GST', calculator: build(:calculator, preferred_amount: 10), zone: create(:zone_with_member)) - adjustment = create(:adjustment, adjustable: @order, amount: 110, included_tax: 10) - - # When I go to the adjustments page for the order - login_to_admin_section - visit spree.admin_orders_path - page.find('td.actions a.icon-edit').click - click_link 'Adjustments' - page.find('td.actions a.icon-edit').click - - # Then I should see the uneditable included tax and our tax rate as the default - page.should have_field :adjustment_included_tax, with: '10.00', disabled: true - page.should have_select :tax_rate_id, selected: 'GST' - - # When I edit the adjustment, removing the tax - select 'Remove tax', from: :tax_rate_id - click_button 'Continue' - - # Then the adjustment tax should be cleared - page.should have_selector 'td.amount', text: '110' - page.should have_selector 'td.included-tax', text: '0' - end - - scenario "modifying an untaxed adjustment on an order" do - # Given a tax rate and an untaxed adjustment - tax_rate = create(:tax_rate, name: 'GST', calculator: build(:calculator, preferred_amount: 10)) - adjustment = create(:adjustment, adjustable: @order, amount: 110, included_tax: 0) - - # When I go to the adjustments page for the order - login_to_admin_section - visit spree.admin_orders_path - page.find('td.actions a.icon-edit').click - click_link 'Adjustments' - page.find('td.actions a.icon-edit').click - - # Then I should see the uneditable included tax and 'Remove tax' as the default tax rate - page.should have_field :adjustment_included_tax, with: '0.00', disabled: true - page.should have_select :tax_rate_id, selected: [] - - # When I edit the adjustment, setting a tax rate - select 'GST', from: :tax_rate_id - click_button 'Continue' - - # Then the adjustment tax should be recalculated - page.should have_selector 'td.amount', text: '110' - page.should have_selector 'td.included-tax', text: '10' - end - context "as an enterprise manager" do let(:coordinator1) { create(:distributor_enterprise) } From f499dd627a9a0797ce8b3246b421e8d053c80718 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 15:32:31 +1100 Subject: [PATCH 46/47] with_tax_included_in_price handles exceptions gracefully --- app/models/spree/tax_rate_decorator.rb | 2 +- spec/models/spree/tax_rate_spec.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/models/spree/tax_rate_decorator.rb b/app/models/spree/tax_rate_decorator.rb index 80bcc450c2..121d379584 100644 --- a/app/models/spree/tax_rate_decorator.rb +++ b/app/models/spree/tax_rate_decorator.rb @@ -51,7 +51,7 @@ module Spree result = yield - # TODO: ensure + ensure self.included_in_price = old_included_in_price calculator.calculable.included_in_price = old_included_in_price diff --git a/spec/models/spree/tax_rate_spec.rb b/spec/models/spree/tax_rate_spec.rb index c10f00ac44..03b2cb39aa 100644 --- a/spec/models/spree/tax_rate_spec.rb +++ b/spec/models/spree/tax_rate_spec.rb @@ -56,6 +56,15 @@ module Spree tax_rate.included_in_price.should be_false tax_rate.calculator.calculable.included_in_price.should be_false end + + it "restores both values when an exception is raised" do + expect do + tax_rate.send(:with_tax_included_in_price) { raise Exception.new 'oops' } + end.to raise_error 'oops' + + tax_rate.included_in_price.should be_false + tax_rate.calculator.calculable.included_in_price.should be_false + end end end end From fb3e292e204b07732095a85bb07590d3c34cecca Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 4 Nov 2015 15:34:30 +1100 Subject: [PATCH 47/47] Formatting --- app/views/spree/admin/adjustments/_edit_form.html.haml | 6 +++--- app/views/spree/admin/adjustments/_new_form.html.haml | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/spree/admin/adjustments/_edit_form.html.haml b/app/views/spree/admin/adjustments/_edit_form.html.haml index 27d2669a4f..5ca71ff9f7 100644 --- a/app/views/spree/admin/adjustments/_edit_form.html.haml +++ b/app/views/spree/admin/adjustments/_edit_form.html.haml @@ -1,17 +1,17 @@ .row - .alpha.three.columns + .alpha.four.columns = f.field_container :amount do = f.label :amount, raw(t(:amount) + content_tag(:span, " *", :class => "required")) = text_field :adjustment, :amount, :class => 'fullwidth' = f.error_message_on :amount - .three.columns + .four.columns = f.field_container :included_tax do = f.label :included_tax, t(:included_tax) = text_field :adjustment, :included_tax, disabled: true, class: 'fullwidth' = f.error_message_on :included_tax - .omega.three.columns + .omega.four.columns = f.field_container :tax_rate_id do = f.label :tax_rate_id, t(:tax_rate) = select_tag :tax_rate_id, options_from_collection_for_select(Spree::TaxRate.all, :id, :name, @tax_rate_id), prompt: t(:remove_tax), class: 'select2 fullwidth' diff --git a/app/views/spree/admin/adjustments/_new_form.html.haml b/app/views/spree/admin/adjustments/_new_form.html.haml index cafce77c5f..a3e831aa8d 100644 --- a/app/views/spree/admin/adjustments/_new_form.html.haml +++ b/app/views/spree/admin/adjustments/_new_form.html.haml @@ -4,11 +4,13 @@ = f.label :amount, raw(t(:amount) + content_tag(:span, " *", :class => "required")) = text_field :adjustment, :amount, :class => 'fullwidth' = f.error_message_on :amount + .omega.three.columns = f.field_container :tax_rate_id do = f.label :tax_rate_id, t(:tax_rate) = select_tag :tax_rate_id, options_from_collection_for_select(Spree::TaxRate.all, :id, :name), prompt: t(:none), class: 'select2 fullwidth' = f.error_message_on :tax_rate_id + .row .alpha.omega.twelve.columns = f.field_container :label do