effective_orders 6.0.1 → 6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 962e704970c3ca1f08dba05993e31abd30c20cdf4e6b18669a7df4a13e8d0893
4
- data.tar.gz: d26a74b26fb06f4840a01c1fef8723b6e8f16cca1d2e0148326f38e34bdc03af
3
+ metadata.gz: baba1d8301ce1a4cafcd81d4bf87c4c88d99f003e850aae91aff2f23bd17b50e
4
+ data.tar.gz: 34f2dd677e1a3a62acc726e6c6210e5645d721bf96df9d9572333bef1039094f
5
5
  SHA512:
6
- metadata.gz: aa72c2a7664bfac304b7950f50461f71820b15d7c4854405c9d2c71c0eea372e104bff9e2af0cdb7d38f7aa1d88819e129ac9d263c57f4030930466a6fd8e882
7
- data.tar.gz: 878903576b4aef842dbe1bef169a4ae5565ed6df7ca61c018591bcb69bbd6b14626c461e7e53a8de6aa77eefa68578e30b9677188deebe35b2b2e11f03bd196b
6
+ metadata.gz: 0bb85d2c07857a4d7c07de089fd85a9b7d6247d0a4bd56aa3f90f88bd3658679f6086bbb7d58acbf2e17850900704d914e299be70f51ae4a5ec5d786ace30ec0
7
+ data.tar.gz: e648b6df06efae5b2050fa701130c3a9b00d1ecac7b2c03345a1c04a997d2dc76c2eeb9b48c1046b040b25be3e9c6efe20a72c174426416e184b4144dc7de6dd
data/README.md CHANGED
@@ -362,6 +362,14 @@ In addition to the above, the following permissions allow access to the `/admin`
362
362
 
363
363
  ```ruby
364
364
  can :admin, :effective_orders # Can access the admin screens
365
+
366
+ can :index, :report_transactions
367
+ can :index, :report_grouped_transactions
368
+ can :index, :report_payment_providers
369
+
370
+ can :index, Admin::ReportTransactionsDatatable
371
+ can :index, Admin::ReportGroupedTransactionsDatatable
372
+ can :index, Admin::ReportPaymentProvidersDatatable
365
373
  ```
366
374
 
367
375
  ## Whats Included
@@ -0,0 +1,36 @@
1
+ module Admin
2
+ class OrderReportsController < ApplicationController
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_orders) }
5
+
6
+ include Effective::CrudController
7
+
8
+ def transactions
9
+ @page_title = 'Revenue: Individual Transactions'
10
+ @datatable = Admin::ReportTransactionsDatatable.new
11
+
12
+ authorize! :index, :report_transactions
13
+
14
+ render 'index'
15
+ end
16
+
17
+ def grouped_transactions
18
+ @page_title = 'Revenue: Grouped Transactions'
19
+ @datatable = Admin::ReportGroupedTransactionsDatatable.new
20
+
21
+ authorize! :index, :report_grouped_transactions
22
+
23
+ render 'index'
24
+ end
25
+
26
+ def payment_providers
27
+ @page_title = 'Revenue: Payment Providers'
28
+ @datatable = Admin::ReportPaymentProvidersDatatable.new
29
+
30
+ authorize! :index, :report_payment_providers
31
+
32
+ render 'index'
33
+ end
34
+
35
+ end
36
+ end
@@ -1,26 +1,28 @@
1
- class Admin::EffectiveCustomersDatatable < Effective::Datatable
2
- datatable do
1
+ module Admin
2
+ class EffectiveCustomersDatatable < Effective::Datatable
3
+ datatable do
3
4
 
4
- col :id, visible: false
5
+ col :id, visible: false
5
6
 
6
- col :user, search: :string
7
+ col :user, search: :string
7
8
 
8
- col :email do |customer|
9
- customer.user.email
10
- end
9
+ col :email do |customer|
10
+ customer.user.email
11
+ end
11
12
 
12
- if EffectiveOrders.stripe?
13
- col :stripe_customer_id
14
- col :active_card
15
- end
13
+ if EffectiveOrders.stripe?
14
+ col :stripe_customer_id
15
+ col :active_card
16
+ end
16
17
 
17
- actions_col do |customer|
18
- link_to('Manage', "https://dashboard.stripe.com/#{'test/' if Rails.env.development?}customers/#{customer.stripe_customer_id}")
19
- end
18
+ actions_col do |customer|
19
+ link_to('Manage', "https://dashboard.stripe.com/#{'test/' if Rails.env.development?}customers/#{customer.stripe_customer_id}")
20
+ end
20
21
 
21
- end
22
+ end
22
23
 
23
- collection do
24
- Effective::Customer.includes(:user).all
24
+ collection do
25
+ Effective::Customer.includes(:user).all
26
+ end
25
27
  end
26
28
  end
@@ -1,119 +1,121 @@
1
- class Admin::EffectiveOrdersDatatable < Effective::Datatable
2
- bulk_actions do
3
- bulk_action(
4
- 'Send payment request email to selected orders',
5
- effective_orders.bulk_send_payment_request_admin_orders_path,
6
- data: { confirm: 'Send payment request emails?' }
7
- )
8
-
9
- bulk_action(
10
- 'Send receipt email to selected purchased orders',
11
- effective_orders.bulk_send_buyer_receipt_orders_path,
12
- data: { confirm: 'Send receipt emails?' }
13
- )
14
- end
1
+ module Admin
2
+ class EffectiveOrdersDatatable < Effective::Datatable
3
+ bulk_actions do
4
+ bulk_action(
5
+ 'Send payment request email to selected orders',
6
+ effective_orders.bulk_send_payment_request_admin_orders_path,
7
+ data: { confirm: 'Send payment request emails?' }
8
+ )
9
+
10
+ bulk_action(
11
+ 'Send receipt email to selected purchased orders',
12
+ effective_orders.bulk_send_buyer_receipt_orders_path,
13
+ data: { confirm: 'Send receipt emails?' }
14
+ )
15
+ end
15
16
 
16
- filters do
17
- unless attributes[:skip_filters]
18
- scope :all
19
- scope :purchased
17
+ filters do
18
+ unless attributes[:skip_filters]
19
+ scope :all
20
+ scope :purchased
20
21
 
21
- scope :deferred if EffectiveOrders.deferred_providers.present?
22
+ scope :deferred if EffectiveOrders.deferred_providers.present?
22
23
 
23
- scope :pending_refunds if EffectiveOrders.refund && !EffectiveOrders.buyer_purchases_refund?
24
- scope :refunds if EffectiveOrders.refund
24
+ scope :pending_refunds if EffectiveOrders.refund && !EffectiveOrders.buyer_purchases_refund?
25
+ scope :refunds if EffectiveOrders.refund
25
26
 
26
- scope :not_purchased
27
+ scope :not_purchased
28
+ end
27
29
  end
28
- end
29
30
 
30
- datatable do
31
- order :updated_at
31
+ datatable do
32
+ order :updated_at
32
33
 
33
- bulk_actions_col
34
+ bulk_actions_col
34
35
 
35
- col :created_at, visible: false
36
- col :updated_at, visible: false
36
+ col :created_at, visible: false
37
+ col :updated_at, visible: false
37
38
 
38
- col :id, label: 'Number' do |order|
39
- '#' + order.to_param
40
- end
39
+ col :id, label: 'Number' do |order|
40
+ '#' + order.to_param
41
+ end
41
42
 
42
- col :purchased_at do |order|
43
- order.purchased_at&.strftime('%F %H:%M') || ('pending refund' if order.pending_refund?) || ("pending #{order.payment_provider}" if order.deferred?) || 'not purchased'
44
- end
43
+ col :purchased_at do |order|
44
+ order.purchased_at&.strftime('%F %H:%M') || ('pending refund' if order.pending_refund?) || ("pending #{order.payment_provider}" if order.deferred?) || 'not purchased'
45
+ end
45
46
 
46
- if attributes[:user_id].blank?
47
- col :user, search: :string
48
- col :billing_name, visible: false
49
- col :email, visible: false
50
- end
47
+ if attributes[:user_id].blank?
48
+ col :user, search: :string
49
+ col :billing_name, visible: false
50
+ col :email, visible: false
51
+ end
51
52
 
52
- col :parent, visible: false, search: :string
53
+ col :parent, visible: false, search: :string
53
54
 
54
- col :cc, visible: false
55
+ col :cc, visible: false
55
56
 
56
- if EffectiveOrders.billing_address
57
- col :billing_address, visible: false
58
- end
57
+ if EffectiveOrders.billing_address
58
+ col :billing_address, visible: false
59
+ end
59
60
 
60
- if EffectiveOrders.shipping_address
61
- col :shipping_address, visible: false
62
- end
61
+ if EffectiveOrders.shipping_address
62
+ col :shipping_address, visible: false
63
+ end
63
64
 
64
- col(:order_items, search: :string).search do |collection, term|
65
- collection.where(id: Effective::OrderItem.where('name ILIKE ?', "%#{term}%").select('order_id'))
66
- end
65
+ col(:order_items, search: :string).search do |collection, term|
66
+ collection.where(id: Effective::OrderItem.where('name ILIKE ?', "%#{term}%").select('order_id'))
67
+ end
67
68
 
68
- col :payment_method
69
- col :payment_provider, label: 'Provider', visible: false, search: { collection: EffectiveOrders.admin_payment_providers }
70
- col :payment_card, label: 'Card', visible: false
69
+ col :payment_method
70
+ col :payment_provider, label: 'Provider', visible: false, search: { collection: EffectiveOrders.admin_payment_providers }
71
+ col :payment_card, label: 'Card', visible: false
71
72
 
72
- col :subtotal, as: :price, visible: false
73
+ col :subtotal, as: :price, visible: false
73
74
 
74
- col :tax, as: :price, visible: false
75
- col(:tax_rate, visible: false) { |order| rate_to_percentage(order.tax_rate) }
75
+ col :tax, as: :price, visible: false
76
+ col(:tax_rate, visible: false) { |order| rate_to_percentage(order.tax_rate) }
76
77
 
77
- col :surcharge, as: :price, visible: false
78
- col(:surcharge_percent, visible: false) { |order| rate_to_percentage(order.surcharge_percent) }
78
+ col :surcharge, as: :price, visible: false
79
+ col(:surcharge_percent, visible: false) { |order| rate_to_percentage(order.surcharge_percent) }
79
80
 
80
- col :total, as: :price
81
+ col :total, as: :price
81
82
 
82
- if EffectiveOrders.collect_note
83
- col :note, visible: false
84
- end
83
+ if EffectiveOrders.collect_note
84
+ col :note, visible: false
85
+ end
85
86
 
86
- col :note_to_buyer, visible: false
87
- col :note_internal, visible: false
87
+ col :note_to_buyer, visible: false
88
+ col :note_internal, visible: false
88
89
 
89
- actions_col partial: 'admin/orders/datatable_actions', partial_as: :order
90
+ actions_col partial: 'admin/orders/datatable_actions', partial_as: :order
91
+
92
+ unless attributes[:total] == false
93
+ aggregate :total
94
+ end
90
95
 
91
- unless attributes[:total] == false
92
- aggregate :total
93
96
  end
94
97
 
95
- end
98
+ collection do
99
+ scope = Effective::Order.all.deep
96
100
 
97
- collection do
98
- scope = Effective::Order.all.deep
101
+ if EffectiveOrders.orders_collection_scope.respond_to?(:call)
102
+ scope = EffectiveOrders.orders_collection_scope.call(scope)
103
+ end
99
104
 
100
- if EffectiveOrders.orders_collection_scope.respond_to?(:call)
101
- scope = EffectiveOrders.orders_collection_scope.call(scope)
102
- end
105
+ if attributes[:user_id].present?
106
+ user_klass = (attributes[:user_type].constantize if attributes[:user_type].present?)
107
+ user_klass ||= current_user.class
103
108
 
104
- if attributes[:user_id].present?
105
- user_klass = (attributes[:user_type].constantize if attributes[:user_type].present?)
106
- user_klass ||= current_user.class
109
+ user = user_klass.find(attributes[:user_id])
110
+ scope = scope.where(user: user)
111
+ end
107
112
 
108
- user = user_klass.find(attributes[:user_id])
109
- scope = scope.where(user: user)
110
- end
113
+ if attributes[:parent_id].present? && attributes[:parent_type].present?
114
+ scope = scope.where(parent_id: attributes[:parent_id], parent_type: attributes[:parent_type])
115
+ end
111
116
 
112
- if attributes[:parent_id].present? && attributes[:parent_type].present?
113
- scope = scope.where(parent_id: attributes[:parent_id], parent_type: attributes[:parent_type])
117
+ scope
114
118
  end
115
119
 
116
- scope
117
120
  end
118
-
119
121
  end
@@ -0,0 +1,78 @@
1
+ # Revenue: Grouped Transactions
2
+
3
+ module Admin
4
+ class ReportGroupedTransactionsDatatable < Effective::Datatable
5
+ filters do
6
+ filter :start_date, nil, as: :date
7
+ filter :end_date, nil, as: :date
8
+ end
9
+
10
+ datatable do
11
+ length 250
12
+
13
+ col :item
14
+ col :subtotal, as: :price
15
+ col :tax, as: :price
16
+ col :total, as: :price
17
+
18
+ payment_providers.each do |provider|
19
+ col(provider, as: :price)
20
+ end
21
+
22
+ col :orders_count
23
+
24
+ col :orders
25
+ col :users
26
+
27
+ col :start_date, as: :date, search: false, sort: false, visible: false do
28
+ date_range.begin&.strftime('%F')
29
+ end
30
+
31
+ col :end_date, as: :date, search: false, sort: false, visible: false do
32
+ date_range.end&.strftime('%F')
33
+ end
34
+
35
+ aggregate :total
36
+ end
37
+
38
+ collection do
39
+ start_date = date_range.begin&.strftime('%F')
40
+ end_date = date_range.end&.strftime('%F')
41
+
42
+ orders = Effective::Order.purchased.where(purchased_at: date_range).where('total != 0')
43
+ order_items = Effective::OrderItem.where(order_id: orders).includes(:purchasable, order: :user)
44
+
45
+ items = order_items.group_by(&:to_s).map do |name, items|
46
+ row = [
47
+ name,
48
+ items.sum { |item| item.subtotal }.to_i,
49
+ items.sum { |item| item.tax }.to_i,
50
+ items.sum { |item| item.total }.to_i,
51
+ ]
52
+
53
+ row += payment_providers.map do |payment_provider|
54
+ items.sum { |item| (item.order.payment_provider == payment_provider) ? item.total : 0 }.to_i
55
+ end
56
+
57
+ row += [
58
+ items.map(&:order_id).uniq.length,
59
+ items.map { |item| item.order },
60
+ items.map { |item| item.order.user },
61
+ start_date,
62
+ end_date
63
+ ]
64
+
65
+ row
66
+ end
67
+ end
68
+
69
+ def payment_providers
70
+ @payment_providers ||= EffectiveOrders.payment_providers - ['free', 'pretend']
71
+ end
72
+
73
+ def date_range
74
+ @date_range ||= (filters[:start_date].presence)..(filters[:end_date].presence)
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,60 @@
1
+ # Revenue: Payment Providers
2
+
3
+ module Admin
4
+ class ReportPaymentProvidersDatatable < Effective::Datatable
5
+ filters do
6
+ filter :start_date, nil, as: :date
7
+ filter :end_date, nil, as: :date
8
+ end
9
+
10
+ datatable do
11
+ length 250
12
+
13
+ col :payment_provider
14
+
15
+ col :sales, as: :price
16
+ col :returns, as: :price
17
+ col :total, as: :price
18
+
19
+ col :start_date, as: :date, search: false, sort: false, visible: false do
20
+ date_range.begin&.strftime('%F')
21
+ end
22
+
23
+ col :end_date, as: :date, search: false, sort: false, visible: false do
24
+ date_range.end&.strftime('%F')
25
+ end
26
+
27
+ aggregate :total
28
+ end
29
+
30
+ collection do
31
+ start_date = date_range.begin&.strftime('%F')
32
+ end_date = date_range.end&.strftime('%F')
33
+
34
+ orders = Effective::Order.purchased.where(purchased_at: date_range).where('total != 0')
35
+ order_items = Effective::OrderItem.where(order_id: orders).includes(:purchasable, order: :user)
36
+
37
+ payment_providers.map do |provider|
38
+ items = order_items.select { |item| item.order.payment_provider == provider }
39
+
40
+ [
41
+ provider,
42
+ items.sum { |item| (item.total > 0 ? item.total : 0) }.to_i,
43
+ items.sum { |item| (item.total < 0 ? item.total : 0) }.to_i,
44
+ items.sum { |item| item.total }.to_i,
45
+ start_date,
46
+ end_date
47
+ ]
48
+ end
49
+ end
50
+
51
+ def payment_providers
52
+ @payment_providers ||= EffectiveOrders.payment_providers - ['free', 'pretend']
53
+ end
54
+
55
+ def date_range
56
+ @date_range ||= (filters[:start_date].presence)..(filters[:end_date].presence)
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,63 @@
1
+ # Revenue: Individual Transactions
2
+
3
+ module Admin
4
+ class ReportTransactionsDatatable < Effective::Datatable
5
+
6
+ filters do
7
+ filter :start_date, nil, as: :date
8
+ filter :end_date, nil, as: :date
9
+ end
10
+
11
+ datatable do
12
+ order :id, :desc
13
+ length 250
14
+
15
+ col :created_at, visible: false
16
+
17
+ col :id, label: 'Order' do |order|
18
+ link_to(order.to_param, effective_orders.admin_order_path(order))
19
+ end
20
+
21
+ col :purchased_at
22
+ col :user
23
+ col :order_items
24
+
25
+ col :subtotal, as: :price
26
+ col :tax, as: :price
27
+ col(:tax_rate) { |order| rate_to_percentage(order.tax_rate) }.aggregate { nil }
28
+
29
+ col :amount_owing, as: :price
30
+
31
+ if EffectiveOrders.surcharge?
32
+ col :surcharge, as: :price
33
+ col(:surcharge_percent) { |order| rate_to_percentage(order.surcharge_percent) }.aggregate { nil }
34
+ end
35
+
36
+ col :total, as: :price
37
+
38
+ col :start_date, as: :date, search: false, sort: false, visible: false do
39
+ date_range.begin&.strftime('%F')
40
+ end
41
+
42
+ col :end_date, as: :date, search: false, sort: false, visible: false do
43
+ date_range.end&.strftime('%F')
44
+ end
45
+
46
+ aggregate :total
47
+
48
+ actions_col
49
+ end
50
+
51
+ collection do
52
+ Effective::Order.purchased
53
+ .where(purchased_at: date_range)
54
+ .where('total != 0')
55
+ .includes(:user, [order_items: :purchasable])
56
+ end
57
+
58
+ def date_range
59
+ @date_range ||= (filters[:start_date].presence)..(filters[:end_date].presence)
60
+ end
61
+
62
+ end
63
+ end
@@ -59,6 +59,10 @@ module Effective
59
59
  (subtotal * order.tax_rate / 100.0).round(0).to_i
60
60
  end
61
61
 
62
+ def amount_owing
63
+ total
64
+ end
65
+
62
66
  def total
63
67
  return subtotal if tax_exempt?
64
68
  raise 'parent Effective::Order must have a tax_rate to compute order item total' unless order.try(:tax_rate).present?
@@ -0,0 +1,3 @@
1
+ %h1.effective-admin-heading= @page_title
2
+
3
+ = render_datatable(@datatable)
data/config/routes.rb CHANGED
@@ -63,6 +63,15 @@ EffectiveOrders::Engine.routes.draw do
63
63
  post 'orders/:id', to: 'orders#update'
64
64
 
65
65
  resources :order_items, only: [:index]
66
+
67
+ resources :order_reports, only: [] do
68
+ collection do
69
+ get :transactions
70
+ get :grouped_transactions
71
+ get :payment_providers
72
+ end
73
+ end
74
+
66
75
  end
67
76
  end
68
77
 
@@ -1,3 +1,3 @@
1
1
  module EffectiveOrders
2
- VERSION = '6.0.1'.freeze
2
+ VERSION = '6.1.0'.freeze
3
3
  end
@@ -188,6 +188,10 @@ module EffectiveOrders
188
188
  use_effective_qb_online && defined?(EffectiveQbOnline)
189
189
  end
190
190
 
191
+ def self.surcharge?
192
+ credit_card_surcharge_percent.to_f > 0.0
193
+ end
194
+
191
195
  def self.mailer_class
192
196
  mailer&.constantize || Effective::OrdersMailer
193
197
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_orders
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.1
4
+ version: 6.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-05 00:00:00.000000000 Z
11
+ date: 2022-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -187,6 +187,7 @@ files:
187
187
  - app/assets/stylesheets/effective_orders/_order.scss
188
188
  - app/controllers/admin/customers_controller.rb
189
189
  - app/controllers/admin/order_items_controller.rb
190
+ - app/controllers/admin/order_reports_controller.rb
190
191
  - app/controllers/admin/orders_controller.rb
191
192
  - app/controllers/effective/carts_controller.rb
192
193
  - app/controllers/effective/concerns/purchase.rb
@@ -207,6 +208,9 @@ files:
207
208
  - app/controllers/effective/webhooks_controller.rb
208
209
  - app/datatables/admin/effective_customers_datatable.rb
209
210
  - app/datatables/admin/effective_orders_datatable.rb
211
+ - app/datatables/admin/report_grouped_transactions_datatable.rb
212
+ - app/datatables/admin/report_payment_providers_datatable.rb
213
+ - app/datatables/admin/report_transactions_datatable.rb
210
214
  - app/datatables/effective_orders_datatable.rb
211
215
  - app/helpers/effective_carts_helper.rb
212
216
  - app/helpers/effective_moneris_checkout_helper.rb
@@ -233,6 +237,7 @@ files:
233
237
  - app/views/admin/customers/index.html.haml
234
238
  - app/views/admin/customers/show.html.haml
235
239
  - app/views/admin/order_items/index.html.haml
240
+ - app/views/admin/order_reports/index.html.haml
236
241
  - app/views/admin/orders/_datatable_actions.html.haml
237
242
  - app/views/admin/orders/_form.html.haml
238
243
  - app/views/admin/orders/_form_note_internal.html.haml