spree_advanced_reporting 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/Gemfile +5 -0
- data/README.md +23 -0
- data/Rakefile +20 -0
- data/TODO.txt +3 -0
- data/app/assets/images/admin/advanced_reporting/asc.gif +0 -0
- data/app/assets/images/admin/advanced_reporting/barchart.png +0 -0
- data/app/assets/images/admin/advanced_reporting/bg.gif +0 -0
- data/app/assets/images/admin/advanced_reporting/close.png +0 -0
- data/app/assets/images/admin/advanced_reporting/desc.gif +0 -0
- data/app/assets/images/admin/advanced_reporting/menu-current-opposite.png +0 -0
- data/app/assets/images/admin/advanced_reporting/open.png +0 -0
- data/app/assets/images/admin/advanced_reporting/save.png +0 -0
- data/app/assets/images/admin/advanced_reporting/search.png +0 -0
- data/app/assets/images/admin/advanced_reporting/usa.png +0 -0
- data/app/assets/images/admin/advanced_reporting/world.png +0 -0
- data/app/assets/javascripts/admin/advanced_reporting/advanced_reporting.js +46 -0
- data/app/assets/javascripts/admin/advanced_reporting/jquery.tablesorter.min.js +4 -0
- data/app/assets/stylesheets/admin/advanced_reporting/advanced_reporting.css.erb +18 -0
- data/app/assets/stylesheets/pdf.css +15 -0
- data/app/controllers/spree/admin/advanced_report_overview_controller.rb +21 -0
- data/app/controllers/spree/admin/reports_controller_decorator.rb +127 -0
- data/app/helpers/advanced_report_helper.rb +13 -0
- data/app/models/ruport/formatter/html_decorator.rb +29 -0
- data/app/models/ruport/formatter/wicked_pdf_decorator.rb +12 -0
- data/app/views/spree/admin/advanced_report_overview/index.html.erb +117 -0
- data/app/views/spree/admin/reports/_advanced_report_criteria.html.erb +64 -0
- data/app/views/spree/admin/reports/geo_base.html.erb +61 -0
- data/app/views/spree/admin/reports/increment_base.html.erb +63 -0
- data/app/views/spree/admin/reports/outstanding.html.erb +16 -0
- data/app/views/spree/admin/reports/top_base.html.erb +17 -0
- data/config/locales/en.yml +96 -0
- data/config/locales/pt-BR.yml +92 -0
- data/config/routes.rb +37 -0
- data/lib/spree/advanced_report.rb +225 -0
- data/lib/spree/advanced_report/geo_report.rb +2 -0
- data/lib/spree/advanced_report/geo_report/geo_profit.rb +44 -0
- data/lib/spree/advanced_report/geo_report/geo_revenue.rb +44 -0
- data/lib/spree/advanced_report/geo_report/geo_units.rb +42 -0
- data/lib/spree/advanced_report/increment_report.rb +78 -0
- data/lib/spree/advanced_report/increment_report/count.rb +33 -0
- data/lib/spree/advanced_report/increment_report/profit.rb +41 -0
- data/lib/spree/advanced_report/increment_report/revenue.rb +40 -0
- data/lib/spree/advanced_report/increment_report/units.rb +33 -0
- data/lib/spree/advanced_report/top_report.rb +2 -0
- data/lib/spree/advanced_report/top_report/top_customers.rb +32 -0
- data/lib/spree/advanced_report/top_report/top_products.rb +35 -0
- data/lib/spree/advanced_report/transaction_report.rb +79 -0
- data/lib/spree_advanced_reporting.rb +25 -0
- data/spree_advanced_reporting.gemspec +22 -0
- metadata +133 -0
| @@ -0,0 +1,225 @@ | |
| 1 | 
            +
            module Spree
         | 
| 2 | 
            +
              class AdvancedReport
         | 
| 3 | 
            +
                include Ruport
         | 
| 4 | 
            +
                attr_accessor :orders, :product_text, :date_text, :taxon_text, :ruportdata, :search,
         | 
| 5 | 
            +
                              :data, :params, :taxon, :product, :product_in_taxon, :unfiltered_params
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def name
         | 
| 8 | 
            +
                  I18n.t("adv_report.base.name")
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def description
         | 
| 12 | 
            +
                  I18n.t("adv_report.base.description")
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def initialize(params)
         | 
| 16 | 
            +
                  # this enables subclasses to provide different defaults to the search
         | 
| 17 | 
            +
                  # by setting the defaults before calling super
         | 
| 18 | 
            +
                  self.params ||= params
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  self.data = {}
         | 
| 21 | 
            +
                  self.ruportdata = {}
         | 
| 22 | 
            +
                  self.unfiltered_params = params[:search].blank? ? {} : params[:search].clone
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  params[:search] ||= {}
         | 
| 25 | 
            +
                  params[:advanced_reporting] ||= {}
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  if Order.count > 0
         | 
| 28 | 
            +
                    begin
         | 
| 29 | 
            +
                      params[:search][:created_at_gt] = Time.zone.parse(params[:search][:created_at_gt]).beginning_of_day
         | 
| 30 | 
            +
                    rescue 
         | 
| 31 | 
            +
                      params[:search][:created_at_gt] = Date.today.beginning_of_day
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    # TODO if lt is defined, and gt is not, gt then should use better default than end of today
         | 
| 35 | 
            +
                    # maybe 24 hours before the defined lt end of day
         | 
| 36 | 
            +
                    
         | 
| 37 | 
            +
                    begin
         | 
| 38 | 
            +
                      params[:search][:created_at_lt] = Time.zone.parse(params[:search][:created_at_lt]).end_of_day
         | 
| 39 | 
            +
                    rescue
         | 
| 40 | 
            +
                      params[:search][:created_at_lt] = Date.today.end_of_day
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  # offer shipped vs completed order filtering
         | 
| 45 | 
            +
                  # in some cases, revenue reports should be based on the time when the revenue
         | 
| 46 | 
            +
                  # is earned (i.e. shipped) not when the order was made or the credit card was processed
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  # it is also important to exclude canceled orders and orders that were not completed
         | 
| 49 | 
            +
                  # before spree 1.1.3 there was a bug that caused Spree::Shipment.shipped_at not be filled
         | 
| 50 | 
            +
                  # easy fix is to copy the completed_at from the order associated with the shipment
         | 
| 51 | 
            +
                  #   https://gist.github.com/3187793#file_shipments_shipped_at_fix.rb
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  filter_address = 'billing'
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  if params[:advanced_reporting][:state_based_on_taxable_address] == '1'
         | 
| 56 | 
            +
                    filter_address = Spree::Config[:tax_using_ship_address] ? 'shipping' : 'billing'
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  if params[:advanced_reporting][:order_type] == 'shipped'
         | 
| 60 | 
            +
                    shipped_search_params = {
         | 
| 61 | 
            +
                      :shipped_at_gt => params[:search][:created_at_gt],
         | 
| 62 | 
            +
                      :shipped_at_lt => params[:search][:created_at_lt],
         | 
| 63 | 
            +
                      :order_state_not_eq => 'canceled',
         | 
| 64 | 
            +
                      :order_completed_at_not_null => true
         | 
| 65 | 
            +
                    }
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                    if params[:advanced_reporting][:state_id].present?
         | 
| 68 | 
            +
                      shipped_search_params[
         | 
| 69 | 
            +
                        filter_address == 'shipping' ? :order_ship_address_state_id_eq : :order_bill_address_state_id_eq
         | 
| 70 | 
            +
                      ] = params[:advanced_reporting][:state_id]
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    # including the ransack predicate will not speed up the SQL query but will not include only fully shipped orders
         | 
| 74 | 
            +
                    only_fully_shipped = params[:advanced_reporting][:shipment] == 'fully_shipped'
         | 
| 75 | 
            +
                    shipped_search_params[:order_inventory_units_shipment_id_not_null] = true if only_fully_shipped
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    # the tricky part here is that orders can have multiple shipments
         | 
| 78 | 
            +
                    # we need to prevent orders from being included twice in the report
         | 
| 79 | 
            +
                    # by choosing to include the order in the earliest report possible
         | 
| 80 | 
            +
                    # (i.e. the first order that shipped) and exclude it from any reports after that
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                    @search = Shipment.includes(:order).search shipped_search_params
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    self.orders = @search.result(:distinct => true).select do |shipment|
         | 
| 85 | 
            +
                      # these manual exclusions could not be done via SQL queries as far as I could tell
         | 
| 86 | 
            +
                      # they are ordered by least to greatest SQL complexity
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                      next true if shipment.order.shipments.size == 1
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                      # if the shipment retrieved is the last shipment shipped for the order, then include the order
         | 
| 91 | 
            +
                      next false if shipment.order.shipments.sort { |a, b| b.shipped_at <=> a.shipped_at }.first == shipment
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                      # conditionally exclude orders which are not fully shipped
         | 
| 94 | 
            +
                      next false if only_fully_shipped && shipment.order.inventory_units.detect { |i| i.shipment.blank? }.blank?
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                      true
         | 
| 97 | 
            +
                    end.map(&:order)
         | 
| 98 | 
            +
                  else
         | 
| 99 | 
            +
                    params[:search][:completed_at_not_null] = true
         | 
| 100 | 
            +
                    params[:search][:state_not_eq] = 'canceled'
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                    if params[:advanced_reporting][:state_id].present?
         | 
| 103 | 
            +
                      params[:search][
         | 
| 104 | 
            +
                        filter_address == 'shipping' ? :ship_address_state_id_eq : :bill_address_state_id_eq
         | 
| 105 | 
            +
                      ] = params[:advanced_reporting][:state_id]
         | 
| 106 | 
            +
                    end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                    only_fully_shipped = params[:advanced_reporting][:shipment] == 'fully_shipped'
         | 
| 109 | 
            +
                    params[:inventory_units_shipment_id_not_null] = true if only_fully_shipped
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                    @search = Order.search(params[:search])
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                    self.orders = @search.result(:distinct => true).select do |order|
         | 
| 114 | 
            +
                      next false if only_fully_shipped && order.inventory_units.detect { |i| i.shipment.blank? }.blank?
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                      true
         | 
| 117 | 
            +
                    end
         | 
| 118 | 
            +
                  end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                  self.product_in_taxon = true
         | 
| 121 | 
            +
                  if params[:advanced_reporting]
         | 
| 122 | 
            +
                    if params[:advanced_reporting][:taxon_id] && params[:advanced_reporting][:taxon_id] != ''
         | 
| 123 | 
            +
                      self.taxon = Taxon.find(params[:advanced_reporting][:taxon_id])
         | 
| 124 | 
            +
                    end
         | 
| 125 | 
            +
                    if params[:advanced_reporting][:product_id] && params[:advanced_reporting][:product_id] != ''
         | 
| 126 | 
            +
                      self.product = Product.find(params[:advanced_reporting][:product_id])
         | 
| 127 | 
            +
                    end
         | 
| 128 | 
            +
                  end
         | 
| 129 | 
            +
                  if self.taxon && self.product && !self.product.taxons.include?(self.taxon)
         | 
| 130 | 
            +
                    self.product_in_taxon = false
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  if self.product
         | 
| 134 | 
            +
                    self.product_text = "Product: #{self.product.name}<br />"
         | 
| 135 | 
            +
                  end
         | 
| 136 | 
            +
                  if self.taxon
         | 
| 137 | 
            +
                    self.taxon_text = "Taxon: #{self.taxon.name}<br />"
         | 
| 138 | 
            +
                  end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                  # Above searchlogic date settings
         | 
| 141 | 
            +
                  self.date_text = "#{I18n.t("adv_report.base.range")}:"
         | 
| 142 | 
            +
                  if self.unfiltered_params
         | 
| 143 | 
            +
                    if self.unfiltered_params[:created_at_gt] != '' && self.unfiltered_params[:created_at_lt] != ''
         | 
| 144 | 
            +
                      self.date_text += " From #{self.unfiltered_params[:created_at_gt]} to #{self.unfiltered_params[:created_at_lt]}"
         | 
| 145 | 
            +
                    elsif self.unfiltered_params[:created_at_gt] != ''
         | 
| 146 | 
            +
                      self.date_text += " After #{self.unfiltered_params[:created_at_gt]}"
         | 
| 147 | 
            +
                    elsif self.unfiltered_params[:created_at_lt] != ''
         | 
| 148 | 
            +
                      self.date_text += " Before #{self.unfiltered_params[:created_at_lt]}"
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                    # TODO this was pulled in from another branch and has some nice internationalization improvements
         | 
| 151 | 
            +
                    # if self.unfiltered_params[:created_at_greater_than] != '' && self.unfiltered_params[:created_at_less_than] != ''
         | 
| 152 | 
            +
                    #   self.date_text += " #{I18n.t("adv_report.base.from")} #{self.unfiltered_params[:created_at_greater_than]} to #{self.unfiltered_params[:created_at_less_than]}"
         | 
| 153 | 
            +
                    # elsif self.unfiltered_params[:created_at_greater_than] != ''
         | 
| 154 | 
            +
                    #   self.date_text += " #{I18n.t("adv_report.base.after")} #{self.unfiltered_params[:created_at_greater_than]}"
         | 
| 155 | 
            +
                    # elsif self.unfiltered_params[:created_at_less_than] != ''
         | 
| 156 | 
            +
                    #   self.date_text += " #{I18n.t("adv_report.base.before")} #{self.unfiltered_params[:created_at_less_than]}"
         | 
| 157 | 
            +
                    else
         | 
| 158 | 
            +
                      self.date_text += " #{I18n.t("adv_report.base.all")}"
         | 
| 159 | 
            +
                    end
         | 
| 160 | 
            +
                  else
         | 
| 161 | 
            +
                    self.date_text += " #{I18n.t("adv_report.base.all")}"
         | 
| 162 | 
            +
                  end
         | 
| 163 | 
            +
                end
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                def download_url(base, format, report_type = nil)
         | 
| 166 | 
            +
                  elements = []
         | 
| 167 | 
            +
                  params[:advanced_reporting] ||= {}
         | 
| 168 | 
            +
                  params[:advanced_reporting]["report_type"] = report_type if report_type
         | 
| 169 | 
            +
                  if params
         | 
| 170 | 
            +
                    [:search, :advanced_reporting].each do |type|
         | 
| 171 | 
            +
                      if params[type]
         | 
| 172 | 
            +
                        params[type].each { |k, v| elements << "#{type}[#{k}]=#{v}" }
         | 
| 173 | 
            +
                      end
         | 
| 174 | 
            +
                    end
         | 
| 175 | 
            +
                  end
         | 
| 176 | 
            +
                  base.gsub!(/^\/\//,'/')
         | 
| 177 | 
            +
                  base + '.' + format + '?' + elements.join('&')
         | 
| 178 | 
            +
                end
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                def revenue(order)
         | 
| 181 | 
            +
                  rev = order.item_total
         | 
| 182 | 
            +
                  if !self.product.nil? && product_in_taxon
         | 
| 183 | 
            +
                    rev = order.line_items.select { |li| li.product == self.product }.inject(0) { |a, b| a += b.quantity * b.price }
         | 
| 184 | 
            +
                  elsif !self.taxon.nil?
         | 
| 185 | 
            +
                    rev = order.line_items.select { |li| li.product && li.product.taxons.include?(self.taxon) }.inject(0) { |a, b| a += b.quantity * b.price }
         | 
| 186 | 
            +
                  end
         | 
| 187 | 
            +
                  adjustment_revenue = order.adjustments.sum(:amount)
         | 
| 188 | 
            +
                  rev += adjustment_revenue if rev > 0
         | 
| 189 | 
            +
                  self.product_in_taxon ? rev : 0
         | 
| 190 | 
            +
                end
         | 
| 191 | 
            +
             | 
| 192 | 
            +
                def profit(order)
         | 
| 193 | 
            +
                  profit = order.line_items.inject(0) { |profit, li| profit + (li.variant.price - li.variant.cost_price.to_f)*li.quantity }
         | 
| 194 | 
            +
                  if !self.product.nil? && product_in_taxon
         | 
| 195 | 
            +
                    profit = order.line_items.select { |li| li.product == self.product }.inject(0) { |profit, li| profit + (li.variant.price - li.variant.cost_price.to_f)*li.quantity }
         | 
| 196 | 
            +
                  elsif !self.taxon.nil?
         | 
| 197 | 
            +
                    profit = order.line_items.select { |li| li.product && li.product.taxons.include?(self.taxon) }.inject(0) { |profit, li| profit + (li.variant.price - li.variant.cost_price.to_f)*li.quantity }
         | 
| 198 | 
            +
                  end
         | 
| 199 | 
            +
                  profit += order.adjustments.sum(:amount)
         | 
| 200 | 
            +
                  self.product_in_taxon ? profit : 0
         | 
| 201 | 
            +
                end
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                def units(order)
         | 
| 204 | 
            +
                  units = order.line_items.sum(:quantity)
         | 
| 205 | 
            +
                  if !self.product.nil? && product_in_taxon
         | 
| 206 | 
            +
                    units = order.line_items.select { |li| li.product == self.product }.inject(0) { |a, b| a += b.quantity }
         | 
| 207 | 
            +
                  elsif !self.taxon.nil?
         | 
| 208 | 
            +
                    units = order.line_items.select { |li| li.product && li.product.taxons.include?(self.taxon) }.inject(0) { |a, b| a += b.quantity }
         | 
| 209 | 
            +
                  end
         | 
| 210 | 
            +
                  self.product_in_taxon ? units : 0
         | 
| 211 | 
            +
                end
         | 
| 212 | 
            +
             | 
| 213 | 
            +
                def order_count(order)
         | 
| 214 | 
            +
                  self.product_in_taxon ? 1 : 0
         | 
| 215 | 
            +
                end
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                def date_range
         | 
| 218 | 
            +
                  if self.params[:search][:created_at_gt].to_date == self.params[:search][:created_at_lt].to_date
         | 
| 219 | 
            +
                    self.params[:search][:created_at_gt].to_date.to_s
         | 
| 220 | 
            +
                  else
         | 
| 221 | 
            +
                    "#{self.params[:search][:created_at_gt].to_date} – #{self.params[:search][:created_at_lt].to_date}"
         | 
| 222 | 
            +
                  end
         | 
| 223 | 
            +
                end
         | 
| 224 | 
            +
              end
         | 
| 225 | 
            +
            end
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            class Spree::AdvancedReport::GeoReport::GeoProfit < Spree::AdvancedReport::GeoReport
         | 
| 2 | 
            +
              def name
         | 
| 3 | 
            +
                I18n.t("adv_report.geo_report.profit.name")
         | 
| 4 | 
            +
              end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def column
         | 
| 7 | 
            +
                I18n.t("adv_report.geo_report.profit.column")
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def description
         | 
| 11 | 
            +
                I18n.t("adv_report.geo_report.profit.description")
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def initialize(params)
         | 
| 15 | 
            +
                super(params)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                data = { :state => {}, :country => {} }
         | 
| 18 | 
            +
                orders.each do |order|
         | 
| 19 | 
            +
                  profit = profit(order)
         | 
| 20 | 
            +
                  if order.bill_address.state
         | 
| 21 | 
            +
                    data[:state][order.bill_address.state_id] ||= {
         | 
| 22 | 
            +
                      :name => order.bill_address.state.name,
         | 
| 23 | 
            +
                      :profit => 0
         | 
| 24 | 
            +
                    }
         | 
| 25 | 
            +
                    data[:state][order.bill_address.state_id][:profit] += profit
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                  if order.bill_address.country
         | 
| 28 | 
            +
                    data[:country][order.bill_address.country_id] ||= {
         | 
| 29 | 
            +
                      :name => order.bill_address.country.name,
         | 
| 30 | 
            +
                      :profit => 0
         | 
| 31 | 
            +
                    }
         | 
| 32 | 
            +
                    data[:country][order.bill_address.country_id][:profit] += profit
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                [:state, :country].each do |type|
         | 
| 37 | 
            +
                  ruportdata[type] = Table(I18n.t("adv_report.geo_report.profit.table"))
         | 
| 38 | 
            +
                  data[type].each { |k, v| ruportdata[type] << { "location" => v[:name], I18n.t("adv_report.profit") => v[:profit] } }
         | 
| 39 | 
            +
                  ruportdata[type].sort_rows_by!([I18n.t("adv_report.profit")], :order => :descending)
         | 
| 40 | 
            +
                  ruportdata[type].rename_column("location", type.to_s.capitalize)
         | 
| 41 | 
            +
                  ruportdata[type].replace_column(I18n.t("adv_report.profit")) { |r| "$%0.2f" % r.send(I18n.t("adv_report.profit")) }
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            class Spree::AdvancedReport::GeoReport::GeoRevenue < Spree::AdvancedReport::GeoReport
         | 
| 2 | 
            +
              def name
         | 
| 3 | 
            +
                I18n.t("adv_report.geo_report.revenue.name")
         | 
| 4 | 
            +
              end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def column
         | 
| 7 | 
            +
                I18n.t("adv_report.geo_report.revenue.column")
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def description
         | 
| 11 | 
            +
                I18n.t("adv_report.geo_report.revenue.description")
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def initialize(params)
         | 
| 15 | 
            +
                super(params)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                data = { :state => {}, :country => {} }
         | 
| 18 | 
            +
                orders.each do |order|
         | 
| 19 | 
            +
                  revenue = revenue(order)
         | 
| 20 | 
            +
                  if order.bill_address.state
         | 
| 21 | 
            +
                    data[:state][order.bill_address.state_id] ||= {
         | 
| 22 | 
            +
                      :name => order.bill_address.state.name,
         | 
| 23 | 
            +
                      :revenue => 0
         | 
| 24 | 
            +
                    }
         | 
| 25 | 
            +
                    data[:state][order.bill_address.state_id][:revenue] += revenue
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                  if order.bill_address.country
         | 
| 28 | 
            +
                    data[:country][order.bill_address.country_id] ||= {
         | 
| 29 | 
            +
                      :name => order.bill_address.country.name,
         | 
| 30 | 
            +
                      :revenue => 0
         | 
| 31 | 
            +
                    }
         | 
| 32 | 
            +
                    data[:country][order.bill_address.country_id][:revenue] += revenue
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                [:state, :country].each do |type|
         | 
| 37 | 
            +
                  ruportdata[type] = Table(I18n.t("adv_report.geo_report.revenue.table"))
         | 
| 38 | 
            +
                  data[type].each { |k, v| ruportdata[type] << { "location" => v[:name], I18n.t("adv_report.revenue") => v[:revenue] } }
         | 
| 39 | 
            +
                  ruportdata[type].sort_rows_by!([I18n.t("adv_report.revenue")], :order => :descending)
         | 
| 40 | 
            +
                  ruportdata[type].rename_column("location", type.to_s.capitalize)
         | 
| 41 | 
            +
                  ruportdata[type].replace_column(I18n.t("adv_report.revenue")) { |r| "$%0.2f" % r.send(I18n.t("adv_report.revenue")) }
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            class Spree::AdvancedReport::GeoReport::GeoUnits < Spree::AdvancedReport::GeoReport
         | 
| 2 | 
            +
              def name
         | 
| 3 | 
            +
                I18n.t("adv_report.geo_report.units.name")
         | 
| 4 | 
            +
              end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def column
         | 
| 7 | 
            +
                I18n.t("adv_report.geo_report.units.column")
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def description
         | 
| 11 | 
            +
                I18n.t("adv_report.geo_report.units.description")
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
              def initialize(params)
         | 
| 14 | 
            +
                super(params)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                data = { :state => {}, :country => {} }
         | 
| 17 | 
            +
                orders.each do |order|
         | 
| 18 | 
            +
                  units = units(order)
         | 
| 19 | 
            +
                  if order.bill_address.state
         | 
| 20 | 
            +
                    data[:state][order.bill_address.state_id] ||= {
         | 
| 21 | 
            +
                      :name => order.bill_address.state.name,
         | 
| 22 | 
            +
                      :units => 0
         | 
| 23 | 
            +
                    }
         | 
| 24 | 
            +
                    data[:state][order.bill_address.state_id][:units] += units
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                  if order.bill_address.country
         | 
| 27 | 
            +
                    data[:country][order.bill_address.country_id] ||= {
         | 
| 28 | 
            +
                      :name => order.bill_address.country.name,
         | 
| 29 | 
            +
                      :units => 0
         | 
| 30 | 
            +
                    }
         | 
| 31 | 
            +
                    data[:country][order.bill_address.country_id][:units] += units
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                [:state, :country].each do |type|
         | 
| 36 | 
            +
                  ruportdata[type] = Table(I18n.t("adv_report.geo_report.units.table"))
         | 
| 37 | 
            +
                  data[type].each { |k, v| ruportdata[type] << { "location" => v[:name], I18n.t("adv_report.units") => v[:units] } }
         | 
| 38 | 
            +
                  ruportdata[type].sort_rows_by!([I18n.t("adv_report.units")], :order => :descending)
         | 
| 39 | 
            +
                  ruportdata[type].rename_column("location", type.to_s.capitalize)
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
            end
         | 
| @@ -0,0 +1,78 @@ | |
| 1 | 
            +
            class Spree::AdvancedReport::IncrementReport < Spree::AdvancedReport
         | 
| 2 | 
            +
              INCREMENTS = I18n.t("adv_report.increments").map(&:to_sym)
         | 
| 3 | 
            +
              attr_accessor :increments, :dates, :total, :all_data
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              def initialize(params)
         | 
| 6 | 
            +
                super(params)
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
                self.increments = INCREMENTS 
         | 
| 9 | 
            +
                self.ruportdata = INCREMENTS.inject({}) { |h, inc| h[inc] = Table(%w[key display value]); h }
         | 
| 10 | 
            +
                self.data = INCREMENTS.inject({}) { |h, inc| h[inc] = {}; h }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                self.dates = {
         | 
| 13 | 
            +
                  I18n.t("adv_report.daily").downcase.to_sym => {
         | 
| 14 | 
            +
                    :date_bucket => "%F",
         | 
| 15 | 
            +
                    :date_display => "%m-%d-%Y",
         | 
| 16 | 
            +
                    :header_display => I18n.t("adv_report.daily"),
         | 
| 17 | 
            +
                  },
         | 
| 18 | 
            +
                  I18n.t("adv_report.weekly").downcase.to_sym => {
         | 
| 19 | 
            +
                    :header_display => I18n.t("adv_report.weekly")
         | 
| 20 | 
            +
                  },
         | 
| 21 | 
            +
                  I18n.t("adv_report.monthly").downcase.to_sym => {
         | 
| 22 | 
            +
                    :date_bucket => "%Y-%m",
         | 
| 23 | 
            +
                    :date_display => "%B %Y",
         | 
| 24 | 
            +
                    :header_display => I18n.t("adv_report.monthly"),
         | 
| 25 | 
            +
                  },
         | 
| 26 | 
            +
                  I18n.t("adv_report.quarterly").downcase.to_sym => {
         | 
| 27 | 
            +
                    :header_display => I18n.t("adv_report.quarterly")
         | 
| 28 | 
            +
                  },
         | 
| 29 | 
            +
                  I18n.t("adv_report.yearly").downcase.to_sym => {
         | 
| 30 | 
            +
                    :date_bucket => "%Y",
         | 
| 31 | 
            +
                    :date_display => "%Y",
         | 
| 32 | 
            +
                    :header_display => I18n.t("adv_report.yearly"),
         | 
| 33 | 
            +
                  }
         | 
| 34 | 
            +
                }
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              def generate_ruport_data
         | 
| 38 | 
            +
                self.all_data = Table(%w[increment key display value]) 
         | 
| 39 | 
            +
                INCREMENTS.each do |inc|
         | 
| 40 | 
            +
                  data[inc].each { |k,v| ruportdata[inc] << { "key" => k, "display" => v[:display], "value" => v[:value] } }
         | 
| 41 | 
            +
                  ruportdata[inc].data.each do |p|
         | 
| 42 | 
            +
                    self.all_data << { "increment" => inc.to_s.capitalize, "key" => p.data["key"], "display" => p.data["display"], "value" => p.data["value"] }
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                  Rails.logger.info "THE DATES #{self.dates} : #{inc}"
         | 
| 45 | 
            +
                  ruportdata[inc].sort_rows_by!(["key"])
         | 
| 46 | 
            +
                  ruportdata[inc].remove_column("key")
         | 
| 47 | 
            +
                  ruportdata[inc].rename_column("display", dates[inc][:header_display])
         | 
| 48 | 
            +
                  ruportdata[inc].rename_column("value", self.name)
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
                self.all_data.sort_rows_by!(["key"])
         | 
| 51 | 
            +
                self.all_data.remove_column("key")
         | 
| 52 | 
            +
                self.all_data = Grouping(self.all_data, :by => "increment") 
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
              
         | 
| 55 | 
            +
              def get_bucket(type, completed_at)
         | 
| 56 | 
            +
                if type == I18n.t("adv_report.weekly").downcase.to_sym
         | 
| 57 | 
            +
                  return completed_at.beginning_of_week.strftime("%Y-%m-%d")
         | 
| 58 | 
            +
                elsif type == I18n.t("adv_report.quarterly").downcase.to_sym
         | 
| 59 | 
            +
                  return completed_at.beginning_of_quarter.strftime("%Y-%m")
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
                completed_at.strftime(dates[type][:date_bucket])
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              def get_display(type, completed_at)
         | 
| 65 | 
            +
                if type == I18n.t("adv_report.weekly").downcase.to_sym
         | 
| 66 | 
            +
                  #funny business
         | 
| 67 | 
            +
                  #next_week = completed_at + 7
         | 
| 68 | 
            +
                  return completed_at.beginning_of_week.strftime("%m-%d-%Y") # + ' - ' + next_week.beginning_of_week.strftime("%m-%d-%Y")
         | 
| 69 | 
            +
                elsif type == I18n.t("adv_report.quarterly").downcase.to_sym
         | 
| 70 | 
            +
                  return completed_at.strftime("%Y") + ' Q' + (completed_at.beginning_of_quarter.strftime("%m").to_i/3 + 1).to_s
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
                completed_at.strftime(dates[type][:date_display])
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              def format_total
         | 
| 76 | 
            +
                self.total 
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
            end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            class Spree::AdvancedReport::IncrementReport::Count < Spree::AdvancedReport::IncrementReport
         | 
| 2 | 
            +
              def name
         | 
| 3 | 
            +
                I18n.t("adv_report.increment_report.count.name")
         | 
| 4 | 
            +
              end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def column
         | 
| 7 | 
            +
                I18n.t("adv_report.increment_report.count.column")
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def description
         | 
| 11 | 
            +
                I18n.t("adv_report.increment_report.count.description")
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def initialize(params)
         | 
| 15 | 
            +
                super(params)
         | 
| 16 | 
            +
                self.total = 0
         | 
| 17 | 
            +
                self.orders.each do |order|
         | 
| 18 | 
            +
                  date = {}
         | 
| 19 | 
            +
                  INCREMENTS.each do |type|
         | 
| 20 | 
            +
                    date[type] = get_bucket(type, order.completed_at)
         | 
| 21 | 
            +
                    data[type][date[type]] ||= {
         | 
| 22 | 
            +
                      :value => 0, 
         | 
| 23 | 
            +
                      :display => get_display(type, order.completed_at),
         | 
| 24 | 
            +
                    }
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                  order_count = order_count(order)
         | 
| 27 | 
            +
                  INCREMENTS.each { |type| data[type][date[type]][:value] += order_count }
         | 
| 28 | 
            +
                  self.total += order_count
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                generate_ruport_data
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         |