mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Merge branch '266reportsbranch' of https://github.com/lin-d-hop/openfoodnetwork into lin-d-hop-266reportsbranch
Conflicts: app/controllers/spree/admin/reports_controller_decorator.rb spec/models/spree/order_spec.rb
This commit is contained in:
@@ -5,6 +5,7 @@ require 'open_food_network/group_buy_report'
|
||||
require 'open_food_network/order_grouper'
|
||||
require 'open_food_network/customers_report'
|
||||
require 'open_food_network/users_and_enterprises_report'
|
||||
require 'open_food_network/order_cycle_management_report'
|
||||
|
||||
Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
@@ -22,11 +23,14 @@ Spree::Admin::ReportsController.class_eval do
|
||||
customers: [
|
||||
["Mailing List", :mailing_list],
|
||||
["Addresses", :addresses]
|
||||
],
|
||||
order_cycle_management: [
|
||||
["Payment Methods Report", :payment_methods_report]
|
||||
]
|
||||
}
|
||||
|
||||
# Fetches user's distributors, suppliers and order_cycles
|
||||
before_filter :load_data, only: [:customers, :products_and_inventory]
|
||||
before_filter :load_data, only: [:customers, :products_and_inventory, :order_cycle_management]
|
||||
|
||||
# Render a partial for orders and fulfillment description
|
||||
respond_override :index => { :html => { :success => lambda {
|
||||
@@ -36,6 +40,8 @@ Spree::Admin::ReportsController.class_eval do
|
||||
render_to_string(partial: 'products_and_inventory_description', layout: false, locals: {report_types: REPORT_TYPES[:products_and_inventory]}).html_safe
|
||||
@reports[:customers][:description] =
|
||||
render_to_string(partial: 'customers_description', layout: false, locals: {report_types: REPORT_TYPES[:customers]}).html_safe
|
||||
@reports[:order_cycle_management][:description] =
|
||||
render_to_string(partial: 'order_cycle_management_description', layout: false, locals: {report_types: REPORT_TYPES[:order_cycle_management]}).html_safe
|
||||
} } }
|
||||
|
||||
|
||||
@@ -54,6 +60,18 @@ Spree::Admin::ReportsController.class_eval do
|
||||
render_report(@report.header, @report.table, params[:csv], "customers.csv")
|
||||
end
|
||||
|
||||
def order_cycle_management
|
||||
@report_types = REPORT_TYPES[:order_cycle_management]
|
||||
@report_type = params[:report_type]
|
||||
@report = OpenFoodNetwork::OrderCycleManagementReport.new spree_current_user, params
|
||||
|
||||
@search = Spree::Order.complete.not_state(:canceled).managed_by(spree_current_user).search(params[:q])
|
||||
|
||||
@orders = @search.result
|
||||
|
||||
render_report(@report.header, @report.table, params[:csv], "customers.csv")
|
||||
end
|
||||
|
||||
def orders_and_distributors
|
||||
params[:q] = {} unless params[:q]
|
||||
|
||||
@@ -621,6 +639,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
:products_and_inventory => {:name => "Products & Inventory", :description => ''},
|
||||
:sales_total => { :name => "Sales Total", :description => "Sales Total For All Orders" },
|
||||
:users_and_enterprises => { :name => "Users & Enterprises", :description => "Enterprise Ownership & Status" }
|
||||
:order_cycle_management => {:name => "Order Cycle Management", :description => ''}
|
||||
}
|
||||
# Return only reports the user is authorized to view.
|
||||
reports.select { |action| can? action, :report }
|
||||
|
||||
@@ -7,5 +7,14 @@ module Spree
|
||||
[ "#{oc.name} (#{orders_open_at} - #{orders_close_at})".html_safe, oc.id ]
|
||||
end
|
||||
end
|
||||
|
||||
def report_payment_method_options(orders)
|
||||
orders.map { |o| o.payments.first.payment_method.andand.name }.uniq
|
||||
end
|
||||
|
||||
def report_shipping_options(orders)
|
||||
orders.map { |o| o.shipping_method.andand.name }.uniq
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -128,7 +128,7 @@ class AbilityDecorator
|
||||
end
|
||||
|
||||
# Reports page
|
||||
can [:admin, :index, :customers, :group_buys, :bulk_coop, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory], :report
|
||||
can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management], :report
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -66,6 +66,12 @@ Spree::Order.class_eval do
|
||||
where("state != ?", state)
|
||||
}
|
||||
|
||||
scope :with_payment_method_name, lambda { |payment_method_name|
|
||||
joins(:payments => :payment_method).
|
||||
where('spree_payment_methods.name = ?', payment_method_name).
|
||||
select('DISTINCT spree_orders.*')
|
||||
}
|
||||
|
||||
|
||||
# -- Methods
|
||||
def products_available_from_new_distribution
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
%ul{style: "margin-left: 12pt"}
|
||||
- report_types.each do |report_type|
|
||||
%li
|
||||
= link_to report_type[0], "#{order_cycle_management_admin_reports_url}?report_type=#{report_type[1]}"
|
||||
@@ -0,0 +1,44 @@
|
||||
= form_tag spree.order_cycle_management_admin_reports_url do |f|
|
||||
%br
|
||||
= label_tag nil, "Order Cycle: "
|
||||
= select_tag(:order_cycle_id,
|
||||
options_for_select(report_order_cycle_options(@order_cycles), params[:order_cycle_id]),
|
||||
include_blank: true)
|
||||
%br
|
||||
%br
|
||||
= label_tag nil, "Payment Methods (hold Ctrl to select multiple payment methods)"
|
||||
%br
|
||||
|
||||
= select_tag(:payment_method_name,
|
||||
options_for_select(report_payment_method_options(@orders), params[:payment_method_name]),
|
||||
multiple: true, include_blank: true)
|
||||
%br
|
||||
%br
|
||||
= label_tag nil, "Shipping Method: "
|
||||
= select_tag(:shipping_method_name,
|
||||
options_for_select(report_shipping_options(@orders), params[:shipping_method_name]),
|
||||
include_blank: true)
|
||||
%br
|
||||
%br
|
||||
= check_box_tag :csv
|
||||
= label_tag :csv, "Download as csv"
|
||||
%br
|
||||
%br
|
||||
= button t(:search)
|
||||
|
||||
%br
|
||||
%br
|
||||
%table#listing_order_payment_methods.index
|
||||
%thead
|
||||
%tr{'data-hook' => "orders_header"}
|
||||
- @report.header.each do |heading|
|
||||
%th=heading
|
||||
%tbody
|
||||
- @report.table.each do |row|
|
||||
%tr
|
||||
- row.each do |column|
|
||||
%td= column
|
||||
- if @report.table.empty?
|
||||
%tr
|
||||
%td{:colspan => "2"}= t(:none)
|
||||
|
||||
@@ -116,6 +116,7 @@ end
|
||||
|
||||
Spree::Core::Engine.routes.prepend do
|
||||
match '/admin/reports/orders_and_distributors' => 'admin/reports#orders_and_distributors', :as => "orders_and_distributors_admin_reports", :via => [:get, :post]
|
||||
match '/admin/reports/order_cycle_management' => 'admin/reports#order_cycle_management', :as => "order_cycle_management_admin_reports", :via => [:get, :post]
|
||||
match '/admin/reports/group_buys' => 'admin/reports#group_buys', :as => "group_buys_admin_reports", :via => [:get, :post]
|
||||
match '/admin/reports/bulk_coop' => 'admin/reports#bulk_coop', :as => "bulk_coop_admin_reports", :via => [:get, :post]
|
||||
match '/admin/reports/payments' => 'admin/reports#payments', :as => "payments_admin_reports", :via => [:get, :post]
|
||||
|
||||
65
lib/open_food_network/order_cycle_management_report.rb
Normal file
65
lib/open_food_network/order_cycle_management_report.rb
Normal file
@@ -0,0 +1,65 @@
|
||||
module OpenFoodNetwork
|
||||
class OrderCycleManagementReport
|
||||
attr_reader :params
|
||||
def initialize(user, params = {})
|
||||
@params = params
|
||||
@user = user
|
||||
end
|
||||
|
||||
def header
|
||||
["First Name", "Last Name", "Email", "Phone", "Hub", "Shipping Method", "Payment Method", "Amount ", "Amount Paid"]
|
||||
|
||||
end
|
||||
|
||||
def table
|
||||
orders.map do |order|
|
||||
ba = order.billing_address
|
||||
da = order.distributor.andand.address
|
||||
[ba.firstname,
|
||||
ba.lastname,
|
||||
order.email,
|
||||
ba.phone,
|
||||
order.distributor.andand.name,
|
||||
order.shipping_method.andand.name,
|
||||
order.payments.first.andand.payment_method.andand.name,
|
||||
order.payments.first.amount
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
def orders
|
||||
filter Spree::Order.managed_by(@user).distributed_by_user(@user).complete.where("spree_orders.state != ?", :canceled)
|
||||
end
|
||||
|
||||
def filter(orders)
|
||||
filter_to_order_cycle filter_to_payment_method filter_to_shipping_method orders
|
||||
end
|
||||
|
||||
def filter_to_payment_method (orders)
|
||||
if params[:payment_method_name].present?
|
||||
orders.with_payment_method_name(params[:payment_method_name])
|
||||
else
|
||||
orders
|
||||
end
|
||||
end
|
||||
|
||||
def filter_to_shipping_method (orders)
|
||||
if params[:shipping_method_name].present?
|
||||
orders.joins(:shipping_method).where("spree_shipping_methods.name = ?", params[:shipping_method_name])
|
||||
else
|
||||
orders
|
||||
end
|
||||
end
|
||||
|
||||
def filter_to_order_cycle(orders)
|
||||
if params[:order_cycle_id].present?
|
||||
orders.where(order_cycle_id: params[:order_cycle_id])
|
||||
else
|
||||
orders
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -59,6 +59,22 @@ feature %q{
|
||||
end
|
||||
end
|
||||
|
||||
describe "Order cycle management report" do
|
||||
before do
|
||||
login_to_admin_section
|
||||
click_link "Reports"
|
||||
end
|
||||
|
||||
scenario "order payment method report" do
|
||||
click_link "Order Cycle Management"
|
||||
rows = find("table#listing_order_payment_methods").all("thead tr")
|
||||
table = rows.map { |r| r.all("th").map { |c| c.text.strip } }
|
||||
table.sort.should == [
|
||||
["First Name", "Last Name", "Email", "Phone", "Hub", "Payment Method", "Amount", "Amount Paid"]
|
||||
].sort
|
||||
end
|
||||
end
|
||||
|
||||
scenario "orders and distributors report" do
|
||||
login_to_admin_section
|
||||
click_link 'Reports'
|
||||
|
||||
121
spec/lib/open_food_network/order_cycle_management_report_spec.rb
Normal file
121
spec/lib/open_food_network/order_cycle_management_report_spec.rb
Normal file
@@ -0,0 +1,121 @@
|
||||
require 'spec_helper'
|
||||
|
||||
include AuthenticationWorkflow
|
||||
|
||||
module OpenFoodNetwork
|
||||
describe OrderCycleManagementReport do
|
||||
context "as a site admin" do
|
||||
let(:user) do
|
||||
user = create(:user)
|
||||
user.spree_roles << Spree::Role.find_or_create_by_name!("admin")
|
||||
user
|
||||
end
|
||||
subject { OrderCycleManagementReport.new user }
|
||||
|
||||
describe "fetching orders" do
|
||||
it "fetches completed orders" do
|
||||
o1 = create(:order)
|
||||
o2 = create(:order, completed_at: 1.day.ago)
|
||||
subject.orders.should == [o2]
|
||||
end
|
||||
|
||||
it "does not show cancelled orders" do
|
||||
o1 = create(:order, state: "canceled", completed_at: 1.day.ago)
|
||||
o2 = create(:order, completed_at: 1.day.ago)
|
||||
subject.orders.should == [o2]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "as an enterprise user" do
|
||||
let!(:user) { create_enterprise_user }
|
||||
|
||||
subject { OrderCycleManagementReport.new user }
|
||||
|
||||
describe "fetching orders" do
|
||||
let(:supplier) { create(:supplier_enterprise) }
|
||||
let(:product) { create(:simple_product, supplier: supplier) }
|
||||
let(:order) { create(:order, completed_at: 1.day.ago) }
|
||||
|
||||
it "only shows orders managed by the current user" do
|
||||
d1 = create(:distributor_enterprise)
|
||||
d1.enterprise_roles.build(user: user).save
|
||||
d2 = create(:distributor_enterprise)
|
||||
d2.enterprise_roles.build(user: create(:user)).save
|
||||
|
||||
o1 = create(:order, distributor: d1, completed_at: 1.day.ago)
|
||||
o2 = create(:order, distributor: d2, completed_at: 1.day.ago)
|
||||
|
||||
subject.should_receive(:filter).with([o1]).and_return([o1])
|
||||
subject.orders.should == [o1]
|
||||
end
|
||||
|
||||
|
||||
it "does not show orders through a hub that the current user does not manage" do
|
||||
# Given a supplier enterprise with an order for one of its products
|
||||
supplier.enterprise_roles.build(user: user).save
|
||||
order.line_items << create(:line_item, product: product)
|
||||
|
||||
# When I fetch orders, I should see no orders
|
||||
subject.should_receive(:filter).with([]).and_return([])
|
||||
subject.orders.should == []
|
||||
end
|
||||
end
|
||||
|
||||
describe "filtering orders" do
|
||||
let!(:orders) { Spree::Order.scoped }
|
||||
let!(:supplier) { create(:supplier_enterprise) }
|
||||
|
||||
let!(:oc1) { create(:simple_order_cycle) }
|
||||
let!(:pm1) { create(:payment_method, name: "PM1") }
|
||||
let!(:sm1) { create(:shipping_method, name: "ship1") }
|
||||
let!(:order1) { create(:order, shipping_method: sm1, order_cycle: oc1) }
|
||||
let!(:payment1) { create(:payment, order: order1, payment_method: pm1) }
|
||||
|
||||
it "returns all orders sans-params" do
|
||||
subject.filter(orders).should == orders
|
||||
end
|
||||
|
||||
it "filters to a specific order cycle" do
|
||||
|
||||
oc2 = create(:simple_order_cycle)
|
||||
order2 = create(:order, order_cycle: oc2)
|
||||
|
||||
subject.stub(:params).and_return(order_cycle_id: oc1.id)
|
||||
subject.filter(orders).should == [order1]
|
||||
end
|
||||
|
||||
it "filters to a payment method" do
|
||||
|
||||
pm2 = create(:payment_method, name: "PM2")
|
||||
order2 = create(:order)
|
||||
payment2 = create(:payment, order: order2, payment_method: pm2)
|
||||
|
||||
subject.stub(:params).and_return(payment_method_name: pm1.name)
|
||||
subject.filter(orders).should == [order1]
|
||||
end
|
||||
|
||||
it "filters to a shipping method" do
|
||||
|
||||
sm2 = create(:shipping_method, name: "ship2")
|
||||
order2 = create(:order, shipping_method: sm2)
|
||||
|
||||
subject.stub(:params).and_return(shipping_method_name: sm1.name)
|
||||
subject.filter(orders).should == [order1]
|
||||
end
|
||||
|
||||
it "should do all the filters at once" do
|
||||
|
||||
subject.stub(:params).and_return(
|
||||
order_cycle_id: oc1.id,
|
||||
shipping_method_name: sm1.name,
|
||||
payment_method_name: pm1.name)
|
||||
subject.filter(orders).should == [order1]
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -77,7 +77,7 @@ describe Spree::Order do
|
||||
subject.update_distribution_charge!
|
||||
end
|
||||
|
||||
it "ensures the correct adjustment(s) are created for order cycles" do
|
||||
it "ensures the correct adjustment(s) are created for order cycles" do
|
||||
EnterpriseFee.stub(:clear_all_adjustments_on_order)
|
||||
line_item = double(:line_item)
|
||||
subject.stub(:line_items) { [line_item] }
|
||||
@@ -328,15 +328,37 @@ describe Spree::Order do
|
||||
end
|
||||
end
|
||||
|
||||
describe "scopes" do
|
||||
describe "scopes" do
|
||||
describe "not_state" do
|
||||
it "finds only orders not in specified state" do
|
||||
o = FactoryGirl.create(:completed_order_with_totals)
|
||||
o.cancel!
|
||||
|
||||
Spree::Order.not_state(:canceled).should_not include o
|
||||
end
|
||||
end
|
||||
|
||||
describe "with payment method name" do
|
||||
let!(:o1) { create(:order) }
|
||||
let!(:o2) { create(:order) }
|
||||
let!(:pm1) { create(:payment_method, name: 'foo') }
|
||||
let!(:pm2) { create(:payment_method, name: 'bar') }
|
||||
let!(:p1) { create(:payment, order: o1, payment_method: pm1) }
|
||||
let!(:p2) { create(:payment, order: o2, payment_method: pm2) }
|
||||
|
||||
it "returns the order with payment method name" do
|
||||
Spree::Order.with_payment_method_name('foo').should == [o1]
|
||||
end
|
||||
|
||||
it "doesn't return rows with a different payment method name" do
|
||||
Spree::Order.with_payment_method_name('foobar').should_not include o1
|
||||
Spree::Order.with_payment_method_name('foobar').should_not include o2
|
||||
end
|
||||
|
||||
it "doesn't return duplicate rows" do
|
||||
p2 = FactoryGirl.create(:payment, :order => o1, :payment_method => pm1)
|
||||
Spree::Order.with_payment_method_name('foo').length.should == 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "shipping address prepopulation" do
|
||||
@@ -385,5 +407,4 @@ describe Spree::Order do
|
||||
create(:order).deliver_order_confirmation_email
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user