From 05437e2a568177b34c94dc5ad24b8dcf3cbf586b Mon Sep 17 00:00:00 2001 From: Paul Mackay Date: Sun, 9 Nov 2014 11:17:46 +0000 Subject: [PATCH 01/28] #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/28] #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/28] #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/28] 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/28] 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/28] #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/28] #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/28] 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/28] #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/28] #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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] #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/28] #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/28] #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/28] 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/28] 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/28] 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/28] 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/28] 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