diff --git a/app/models/spree/address.rb b/app/models/spree/address.rb index 3538336d7d..e4dd2cf5ed 100644 --- a/app/models/spree/address.rb +++ b/app/models/spree/address.rb @@ -105,6 +105,10 @@ module Spree render_address([city, zipcode, state&.name]) end + def address_and_city + [address1, address2, city].select(&:present?).join(' ') + end + private def require_zipcode? diff --git a/app/views/admin/reports/filters/_order_cycle_management.html.haml b/app/views/admin/reports/filters/_order_cycle_management.html.haml index dc3977266c..3699b5cc63 100644 --- a/app/views/admin/reports/filters/_order_cycle_management.html.haml +++ b/app/views/admin/reports/filters/_order_cycle_management.html.haml @@ -11,8 +11,8 @@ .row .alpha.two.columns= label_tag nil, t(:report_payment) - .omega.fourteen.columns= select_tag(:payment_method_in, options_for_select(report_payment_method_options(@report.orders), params[:payment_method_in]), {class: "select2 fullwidth", multiple: true}) + .omega.fourteen.columns= select_tag(:payment_method_in, options_for_select(report_payment_method_options(@report.query_result), params[:payment_method_in]), {class: "select2 fullwidth", multiple: true}) .row - .alpha.two.columns= label_tag nil, "#{t(:shipping_methods)}: " - .omega.fourteen.columns= select_tag(:shipping_method_in, options_for_select(report_shipping_method_options(@report.orders), params[:shipping_method_in]), {class: "select2 fullwidth", multiple: true}) + .alpha.two.columns= label_tag nil, t(:shipping_methods) + .omega.fourteen.columns= select_tag(:shipping_method_in, options_for_select(report_shipping_method_options(@report.query_result), params[:shipping_method_in]), {class: "select2 fullwidth", multiple: true}) diff --git a/lib/reporting/reports/customers/addresses.rb b/lib/reporting/reports/customers/addresses.rb index e51edc9aee..fa024c446d 100644 --- a/lib/reporting/reports/customers/addresses.rb +++ b/lib/reporting/reports/customers/addresses.rb @@ -8,20 +8,14 @@ module Reporting { first_name: proc { |order| order.billing_address.firstname }, last_name: proc { |order| order.billing_address.lastname }, - billing_address: proc { |order| address_from(order.billing_address) }, + billing_address: proc { |order| order.billing_address.address_and_city }, email: proc { |order| order.email }, phone: proc { |order| order.billing_address.phone }, hub: proc { |order| order.distributor&.name }, - hub_address: proc { |order| address_from(order.distributor&.address) }, + hub_address: proc { |order| order.distributor&.address&.address_and_city }, shipping_method: proc { |order| order.shipping_method&.name }, } end - - private - - def address_from(address) - [address&.address1, address&.address2, address&.city].join(" ") - end end end end diff --git a/lib/reporting/reports/order_cycle_management/base.rb b/lib/reporting/reports/order_cycle_management/base.rb new file mode 100644 index 0000000000..5101285beb --- /dev/null +++ b/lib/reporting/reports/order_cycle_management/base.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +module Reporting + module Reports + module OrderCycleManagement + class Base < ReportObjectTemplate + DEFAULT_DATE_INTERVAL = { from: -1.month, to: 1.day }.freeze + + def initialize(user, params = {}) + super(user, params) + params[:q] ||= {} + params[:q][:completed_at_gt] ||= Time.zone.today + DEFAULT_DATE_INTERVAL[:from] + params[:q][:completed_at_lt] ||= Time.zone.today + DEFAULT_DATE_INTERVAL[:to] + end + + def search + Spree::Order. + finalized. + not_state(:canceled). + distributed_by_user(@user). + managed_by(@user). + ransack(params[:q]) + end + + # This result is used in _order_cucle_management.html so caching it + def query_result + @query_result ||= orders + end + + def orders + search_result = search.result.order(:completed_at) + orders = OutstandingBalance.new(search_result).query.select('spree_orders.*') + + filter(orders) + end + + def filter(orders) + filter_to_payment_method filter_to_shipping_method filter_to_order_cycle orders + end + + private + + def filter_to_payment_method(orders) + if params[:payment_method_in].present? + orders + .joins(payments: :payment_method) + .where(spree_payments: { payment_method_id: params[:payment_method_in] }) + else + orders + end + end + + def filter_to_shipping_method(orders) + if params[:shipping_method_in].present? + orders + .joins(shipments: :shipping_rates) + .where(spree_shipping_rates: { + selected: true, + shipping_method_id: params[:shipping_method_in] + }) + 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 + + def customer_code(email) + customer = Customer.where(email: email).first + customer.nil? ? "" : customer.code + end + end + end + end +end diff --git a/lib/reporting/reports/order_cycle_management/delivery.rb b/lib/reporting/reports/order_cycle_management/delivery.rb new file mode 100644 index 0000000000..3208ce7624 --- /dev/null +++ b/lib/reporting/reports/order_cycle_management/delivery.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Reporting + module Reports + module OrderCycleManagement + class Delivery < Base + # rubocop:disable Metrics/AbcSize + def columns + { + first_name: proc { |order| order.shipping_address.firstname }, + last_name: proc { |order| order.shipping_address.lastname }, + hub: proc { |order| order.distributor&.name }, + customer_code: proc { |order| customer_code(order.email) }, + delivery_address: proc { |order| order.shipping_address.address_and_city }, + delivery_postcode: proc { |order| order.shipping_address.zipcode }, + phone: proc { |order| order.shipping_address.phone }, + shipping_method: proc { |order| order.shipping_method&.name }, + payment_method: proc { |order| order.payments.first&.payment_method&.name }, + amount: proc { |order| order.total }, + balance: proc { |order| order.balance_value }, + temp_controlled_items: proc { |order| has_temperature_controlled_items?(order) }, + special_instructions: proc { |order| order.special_instructions }, + } + end + # rubocop:enable Metrics/AbcSize + + def has_temperature_controlled_items?(order) + order.line_items.any? { |line_item| + line_item.product.shipping_category&.temperature_controlled + } + end + end + end + end +end diff --git a/lib/reporting/reports/order_cycle_management/order_cycle_management_report.rb b/lib/reporting/reports/order_cycle_management/order_cycle_management_report.rb deleted file mode 100644 index 9236725549..0000000000 --- a/lib/reporting/reports/order_cycle_management/order_cycle_management_report.rb +++ /dev/null @@ -1,160 +0,0 @@ -# frozen_string_literal: true - -module Reporting - module Reports - module OrderCycleManagement - class OrderCycleManagementReport < ReportObjectTemplate - DEFAULT_DATE_INTERVAL = { from: -1.month, to: 1.day }.freeze - - def initialize(user, params = {}) - super(user, params) - params[:q] ||= {} - params[:q][:completed_at_gt] ||= Time.zone.today + DEFAULT_DATE_INTERVAL[:from] - params[:q][:completed_at_lt] ||= Time.zone.today + DEFAULT_DATE_INTERVAL[:to] - end - - def table_headers - if is_payment_methods? - [ - I18n.t(:report_header_first_name), - I18n.t(:report_header_last_name), - I18n.t(:report_header_hub), - I18n.t(:report_header_hub_code), - I18n.t(:report_header_email), - I18n.t(:report_header_phone), - I18n.t(:report_header_shipping_method), - I18n.t(:report_header_payment_method), - I18n.t(:report_header_amount), - I18n.t(:report_header_balance), - ] - else - [ - I18n.t(:report_header_first_name), - I18n.t(:report_header_last_name), - I18n.t(:report_header_hub), - I18n.t(:report_header_hub_code), - I18n.t(:report_header_delivery_address), - I18n.t(:report_header_delivery_postcode), - I18n.t(:report_header_phone), - I18n.t(:report_header_shipping_method), - I18n.t(:report_header_payment_method), - I18n.t(:report_header_amount), - I18n.t(:report_header_balance), - I18n.t(:report_header_temp_controlled_items), - I18n.t(:report_header_special_instructions), - ] - end - end - - def search - Spree::Order. - finalized. - not_state(:canceled). - distributed_by_user(@user). - managed_by(@user). - ransack(params[:q]) - end - - def orders - search_result = search.result.order(:completed_at) - orders_with_balance = OutstandingBalance.new(search_result). - query. - select('spree_orders.*') - - filter(orders_with_balance) - end - - def table_rows - if is_payment_methods? - orders.map { |o| payment_method_row o } - else - orders.map { |o| delivery_row o } - end - end - - def filter(search_result) - filter_to_payment_method filter_to_shipping_method filter_to_order_cycle search_result - end - - private - - # This method relies on `balance_value` as a computed DB column. See `CompleteOrdersWithBalance` - # for reference. - def balance(order) - order.balance_value - end - - def payment_method_row(order) - ba = order.billing_address - [ba&.firstname, - ba&.lastname, - order.distributor&.name, - customer_code(order.email), - order.email, - ba&.phone, - order.shipping_method&.name, - order.payments.last&.payment_method&.name, - order.total, - balance(order)] - end - - def delivery_row(order) - sa = order.shipping_address - [sa.firstname, - sa.lastname, - order.distributor&.name, - customer_code(order.email), - "#{sa.address1} #{sa.address2} #{sa.city}", - sa.zipcode, - sa.phone, - order.shipping_method&.name, - order.payments.first&.payment_method&.name, - order.total, - balance(order), - has_temperature_controlled_items?(order), - order.special_instructions] - end - - def filter_to_payment_method(orders) - if params[:payment_method_in].present? - orders.joins(payments: :payment_method).where(spree_payments: { payment_method_id: params[:payment_method_in] }) - else - orders - end - end - - def filter_to_shipping_method(orders) - if params[:shipping_method_in].present? - orders.joins(shipments: :shipping_rates).where(spree_shipping_rates: { selected: true, - shipping_method_id: params[:shipping_method_in] }) - 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 - - def has_temperature_controlled_items?(order) - order.line_items.any? { |line_item| - line_item.product.shipping_category&.temperature_controlled - } - end - - def is_payment_methods? - params[:report_subtype] == "payment_methods" - end - - def customer_code(email) - customer = Customer.where(email: email).first - customer.nil? ? "" : customer.code - end - end - end - end -end diff --git a/lib/reporting/reports/order_cycle_management/payment_methods.rb b/lib/reporting/reports/order_cycle_management/payment_methods.rb new file mode 100644 index 0000000000..6556d762e5 --- /dev/null +++ b/lib/reporting/reports/order_cycle_management/payment_methods.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Reporting + module Reports + module OrderCycleManagement + class PaymentMethods < Base + # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/CyclomaticComplexity + def columns + { + first_name: proc { |order| order.billing_address&.firstname }, + last_name: proc { |order| order.billing_address&.lastname }, + hub: proc { |order| order.distributor&.name }, + customer_code: proc { |order| customer_code(order.email) }, + email: proc { |order| order.email }, + phone: proc { |order| order.billing_address&.phone }, + shipping_method: proc { |order| order.shipping_method&.name }, + payment_method: proc { |order| order.payments.last&.payment_method&.name }, + amount: proc { |order| order.total }, + balance: proc { |order| order.balance_value }, + } + end + # rubocop:enable Metrics/AbcSize + # rubocop:enable Metrics/CyclomaticComplexity + end + end + end +end diff --git a/spec/lib/reports/order_cycle_management_report_spec.rb b/spec/lib/reports/order_cycle_management_report_spec.rb index 9cdb4846e8..8676d7795f 100644 --- a/spec/lib/reports/order_cycle_management_report_spec.rb +++ b/spec/lib/reports/order_cycle_management_report_spec.rb @@ -5,9 +5,9 @@ require 'spec_helper' module Reporting module Reports module OrderCycleManagement - describe OrderCycleManagementReport do + describe Base do context "as a site admin" do - subject { OrderCycleManagementReport.new(user, params) } + subject { Base.new(user, params) } let(:params) { {} } let(:user) do @@ -63,7 +63,7 @@ module Reporting context "as an enterprise user" do let!(:user) { create(:user) } - subject { OrderCycleManagementReport.new user, {} } + subject { Base.new user, {} } describe "fetching orders" do let(:supplier) { create(:supplier_enterprise) } @@ -148,13 +148,13 @@ module Reporting end describe '#table_rows' do - subject { OrderCycleManagementReport.new(user, params) } + subject { Base.new(user, params) } let(:distributor) { create(:distributor_enterprise) } before { distributor.enterprise_roles.create!(user: user) } context 'when the report type is payment_methods' do - let(:params) { { report_subtype: 'payment_methods' } } + subject { PaymentMethods.new(user) } let!(:order) do create( @@ -180,8 +180,8 @@ module Reporting end end - context 'when the report type is not payment_methods' do - let(:params) { {} } + context 'when the report type is delivery' do + subject { Delivery.new(user) } let!(:order) do create( :completed_order_with_totals, diff --git a/spec/system/admin/reports_spec.rb b/spec/system/admin/reports_spec.rb index db6f7e9ba2..679eebc830 100644 --- a/spec/system/admin/reports_spec.rb +++ b/spec/system/admin/reports_spec.rb @@ -73,7 +73,7 @@ describe ' rows = find("table.report__table").all("thead tr") table = rows.map { |r| r.all("th").map { |c| c.text.strip } } expect(table.sort).to eq([ - ["First Name", "Last Name", "Hub", "Hub Code", "Email", "Phone", "Shipping Method", + ["First Name", "Last Name", "Hub", "Customer Code", "Email", "Phone", "Shipping Method", "Payment Method", "Amount", "Balance"].map(&:upcase) ].sort) end @@ -84,7 +84,7 @@ describe ' rows = find("table.report__table").all("thead tr") table = rows.map { |r| r.all("th").map { |c| c.text.strip } } expect(table.sort).to eq([ - ["First Name", "Last Name", "Hub", "Hub Code", "Delivery Address", "Delivery Postcode", + ["First Name", "Last Name", "Hub", "Customer Code", "Delivery Address", "Delivery Postcode", "Phone", "Shipping Method", "Payment Method", "Amount", "Balance", "Temp Controlled Items?", "Special Instructions"].map(&:upcase) ].sort)