2022-08-29 17:34:09 +02:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
# Fetch data from the PostgreSQL database and prepare them
|
|
|
|
# to be used in the statistics generation
|
|
|
|
class Statistics::FetcherService
|
|
|
|
include Statistics::Concerns::HelpersConcern
|
|
|
|
include Statistics::Concerns::ComputeConcern
|
2022-09-05 15:14:08 +02:00
|
|
|
include Statistics::Concerns::ProjectsConcern
|
2022-10-11 15:14:53 +02:00
|
|
|
include Statistics::Concerns::StoreOrdersConcern
|
2022-08-29 17:34:09 +02:00
|
|
|
|
|
|
|
class << self
|
|
|
|
def subscriptions_list(options = default_options)
|
|
|
|
result = []
|
|
|
|
InvoiceItem.where("object_type = '#{Subscription.name}' AND invoice_items.created_at >= :start_date " \
|
|
|
|
'AND invoice_items.created_at <= :end_date', options)
|
|
|
|
.eager_load(invoice: [:coupon]).each do |i|
|
|
|
|
next if i.invoice.is_a?(Avoir)
|
|
|
|
|
|
|
|
sub = i.object
|
|
|
|
|
|
|
|
ca = i.amount.to_i
|
|
|
|
cs = CouponService.new
|
|
|
|
ca = cs.ventilate(cs.invoice_total_no_coupon(i.invoice), ca, i.invoice.coupon) unless i.invoice.coupon_id.nil?
|
|
|
|
ca /= 100.00
|
|
|
|
profile = sub.statistic_profile
|
|
|
|
p = sub.plan
|
2022-10-10 12:20:39 +02:00
|
|
|
result.push({ date: i.created_at.to_date,
|
2022-08-29 17:34:09 +02:00
|
|
|
plan: p.group.slug,
|
|
|
|
plan_id: p.id,
|
|
|
|
plan_interval: p.interval,
|
|
|
|
plan_interval_count: p.interval_count,
|
|
|
|
plan_group_name: p.group.name,
|
|
|
|
slug: p.slug,
|
|
|
|
duration: p.find_statistic_type.key,
|
|
|
|
subscription_id: sub.id,
|
|
|
|
invoice_item_id: i.id,
|
|
|
|
ca: ca }.merge(user_info(profile)))
|
|
|
|
end
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def reservations_machine_list(options = default_options)
|
|
|
|
result = []
|
|
|
|
Reservation
|
|
|
|
.where("reservable_type = 'Machine' AND slots_reservations.canceled_at IS NULL AND " \
|
|
|
|
'reservations.created_at >= :start_date AND reservations.created_at <= :end_date', options)
|
|
|
|
.eager_load(:slots, :slots_reservations, :invoice_items, statistic_profile: [:group])
|
|
|
|
.each do |r|
|
|
|
|
next unless r.reservable
|
|
|
|
|
|
|
|
profile = r.statistic_profile
|
2022-10-10 12:20:39 +02:00
|
|
|
result.push({ date: r.created_at.to_date,
|
2022-08-29 17:34:09 +02:00
|
|
|
reservation_id: r.id,
|
|
|
|
machine_id: r.reservable.id,
|
|
|
|
machine_type: r.reservable.friendly_id,
|
|
|
|
machine_name: r.reservable.name,
|
2023-01-31 17:10:07 +01:00
|
|
|
slot_dates: r.slots.map(&:start_at).map(&:to_date),
|
|
|
|
nb_hours: (r.slots.map(&:duration).map(&:to_i).reduce(:+) / 3600.0).to_i,
|
2022-08-29 17:34:09 +02:00
|
|
|
ca: calcul_ca(r.original_invoice) }.merge(user_info(profile)))
|
|
|
|
end
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def reservations_space_list(options = default_options)
|
|
|
|
result = []
|
|
|
|
Reservation
|
|
|
|
.where("reservable_type = 'Space' AND slots_reservations.canceled_at IS NULL AND " \
|
|
|
|
'reservations.created_at >= :start_date AND reservations.created_at <= :end_date', options)
|
|
|
|
.eager_load(:slots, :slots_reservations, :invoice_items, statistic_profile: [:group])
|
|
|
|
.each do |r|
|
|
|
|
next unless r.reservable
|
|
|
|
|
|
|
|
profile = r.statistic_profile
|
2022-10-10 12:20:39 +02:00
|
|
|
result.push({ date: r.created_at.to_date,
|
2022-08-29 17:34:09 +02:00
|
|
|
reservation_id: r.id,
|
|
|
|
space_id: r.reservable.id,
|
|
|
|
space_name: r.reservable.name,
|
|
|
|
space_type: r.reservable.slug,
|
2023-01-31 17:10:07 +01:00
|
|
|
slot_dates: r.slots.map(&:start_at).map(&:to_date),
|
|
|
|
nb_hours: (r.slots.map(&:duration).map(&:to_i).reduce(:+) / 3600.0).to_i,
|
2022-08-29 17:34:09 +02:00
|
|
|
ca: calcul_ca(r.original_invoice) }.merge(user_info(profile)))
|
|
|
|
end
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def reservations_training_list(options = default_options)
|
|
|
|
result = []
|
|
|
|
Reservation
|
|
|
|
.where("reservable_type = 'Training' AND slots_reservations.canceled_at IS NULL AND " \
|
|
|
|
'reservations.created_at >= :start_date AND reservations.created_at <= :end_date', options)
|
|
|
|
.eager_load(:slots, :slots_reservations, :invoice_items, statistic_profile: [:group])
|
|
|
|
.each do |r|
|
|
|
|
next unless r.reservable
|
|
|
|
|
|
|
|
profile = r.statistic_profile
|
|
|
|
slot = r.slots.first
|
2022-10-10 12:20:39 +02:00
|
|
|
result.push({ date: r.created_at.to_date,
|
2022-08-29 17:34:09 +02:00
|
|
|
reservation_id: r.id,
|
|
|
|
training_id: r.reservable.id,
|
|
|
|
training_type: r.reservable.friendly_id,
|
|
|
|
training_name: r.reservable.name,
|
|
|
|
training_date: slot.start_at.to_date,
|
|
|
|
nb_hours: difference_in_hours(slot.start_at, slot.end_at),
|
|
|
|
ca: calcul_ca(r.original_invoice) }.merge(user_info(profile)))
|
|
|
|
end
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def reservations_event_list(options = default_options)
|
|
|
|
result = []
|
|
|
|
Reservation
|
|
|
|
.where("reservable_type = 'Event' AND slots_reservations.canceled_at IS NULL AND " \
|
|
|
|
'reservations.created_at >= :start_date AND reservations.created_at <= :end_date', options)
|
|
|
|
.eager_load(:slots, :slots_reservations, :invoice_items, statistic_profile: [:group])
|
|
|
|
.each do |r|
|
|
|
|
next unless r.reservable
|
|
|
|
|
|
|
|
profile = r.statistic_profile
|
|
|
|
slot = r.slots.first
|
2022-10-10 12:20:39 +02:00
|
|
|
result.push({ date: r.created_at.to_date,
|
2022-08-29 17:34:09 +02:00
|
|
|
reservation_id: r.id,
|
|
|
|
event_id: r.reservable.id,
|
|
|
|
event_type: r.reservable.category.slug,
|
|
|
|
event_name: r.reservable.name,
|
|
|
|
event_date: slot.start_at.to_date,
|
|
|
|
event_theme: (r.reservable.event_themes.first ? r.reservable.event_themes.first.name : ''),
|
|
|
|
age_range: (r.reservable.age_range_id ? r.reservable.age_range.name : ''),
|
|
|
|
nb_places: r.total_booked_seats,
|
|
|
|
nb_hours: difference_in_hours(slot.start_at, slot.end_at),
|
|
|
|
ca: calcul_ca(r.original_invoice) }.merge(user_info(profile)))
|
|
|
|
end
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def members_ca_list(options = default_options)
|
|
|
|
subscriptions_ca_list = subscriptions_list(options)
|
|
|
|
reservations_ca_list = []
|
|
|
|
avoirs_ca_list = []
|
|
|
|
users_list = []
|
|
|
|
Reservation.where('reservations.created_at >= :start_date AND reservations.created_at <= :end_date', options)
|
|
|
|
.eager_load(:slots, :invoice_items, statistic_profile: [:group])
|
|
|
|
.each do |r|
|
|
|
|
next unless r.reservable
|
|
|
|
|
|
|
|
reservations_ca_list.push(
|
2022-10-10 12:20:39 +02:00
|
|
|
{ date: r.created_at.to_date, ca: calcul_ca(r.original_invoice) || 0 }.merge(user_info(r.statistic_profile))
|
2022-08-29 17:34:09 +02:00
|
|
|
)
|
|
|
|
end
|
|
|
|
Avoir.where('invoices.created_at >= :start_date AND invoices.created_at <= :end_date', options)
|
|
|
|
.eager_load(:invoice_items, statistic_profile: [:group])
|
|
|
|
.each do |i|
|
|
|
|
# the following line is a workaround for issue #196
|
|
|
|
profile = i.statistic_profile || i.main_item.object&.wallet&.user&.statistic_profile
|
2022-10-10 12:20:39 +02:00
|
|
|
avoirs_ca_list.push({ date: i.created_at.to_date, ca: calcul_avoir_ca(i) || 0 }.merge(user_info(profile)))
|
2022-08-29 17:34:09 +02:00
|
|
|
end
|
|
|
|
reservations_ca_list.concat(subscriptions_ca_list).concat(avoirs_ca_list).each do |e|
|
|
|
|
profile = StatisticProfile.find(e[:statistic_profile_id])
|
|
|
|
u = find_or_create_user_info(profile, users_list)
|
2022-10-10 12:20:39 +02:00
|
|
|
u[:date] = e[:date]
|
2022-08-29 17:34:09 +02:00
|
|
|
add_ca(u, e[:ca], users_list)
|
|
|
|
end
|
|
|
|
users_list
|
|
|
|
end
|
|
|
|
|
|
|
|
def members_list(options = default_options)
|
|
|
|
result = []
|
|
|
|
member = Role.find_by(name: 'member')
|
|
|
|
StatisticProfile.where('role_id = :member AND created_at >= :start_date AND created_at <= :end_date',
|
|
|
|
options.merge(member: member.id))
|
|
|
|
.each do |sp|
|
|
|
|
next if sp.user&.need_completion?
|
|
|
|
|
2022-10-10 12:20:39 +02:00
|
|
|
result.push({ date: sp.created_at.to_date }.merge(user_info(sp)))
|
2022-08-29 17:34:09 +02:00
|
|
|
end
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def projects_list(options = default_options)
|
|
|
|
result = []
|
|
|
|
Project.where('projects.published_at >= :start_date AND projects.published_at <= :end_date', options)
|
|
|
|
.eager_load(:licence, :themes, :components, :machines, :project_users, author: [:group])
|
|
|
|
.each do |p|
|
2022-10-10 12:20:39 +02:00
|
|
|
result.push({ date: p.created_at.to_date }.merge(user_info(p.author)).merge(project_info(p)))
|
2022-08-29 17:34:09 +02:00
|
|
|
end
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2022-10-12 11:42:15 +02:00
|
|
|
def store_orders_list(states, options = default_options)
|
2022-10-10 17:42:25 +02:00
|
|
|
result = []
|
|
|
|
Order.includes(order_items: [:orderable])
|
2022-10-11 17:23:45 +02:00
|
|
|
.joins(:order_items, :order_activities)
|
2022-10-12 11:42:15 +02:00
|
|
|
.where(order_items: { orderable_type: 'Product' })
|
|
|
|
.where(orders: { state: states })
|
2022-10-11 17:23:45 +02:00
|
|
|
.where('order_activities.created_at >= :start_date AND order_activities.created_at <= :end_date', options)
|
2022-10-12 11:42:15 +02:00
|
|
|
.group('orders.id')
|
2022-10-10 17:42:25 +02:00
|
|
|
.each do |o|
|
|
|
|
result.push({ date: o.created_at.to_date, ca: calcul_ca(o.invoice) }
|
|
|
|
.merge(user_info(o.statistic_profile))
|
|
|
|
.merge(store_order_info(o)))
|
|
|
|
end
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2022-08-29 17:34:09 +02:00
|
|
|
private
|
|
|
|
|
|
|
|
def add_ca(profile, new_ca, users_list)
|
|
|
|
if profile[:ca]
|
|
|
|
profile[:ca] += new_ca || 0
|
|
|
|
else
|
|
|
|
profile[:ca] = new_ca || 0
|
|
|
|
users_list.push profile
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def find_or_create_user_info(profile, list)
|
|
|
|
found = list.find do |l|
|
|
|
|
l[:statistic_profile_id] == profile.id
|
|
|
|
end
|
|
|
|
found || user_info(profile)
|
|
|
|
end
|
|
|
|
|
|
|
|
def user_info(statistic_profile)
|
|
|
|
return {} unless statistic_profile
|
|
|
|
|
|
|
|
{
|
|
|
|
statistic_profile_id: statistic_profile.id,
|
|
|
|
user_id: statistic_profile.user_id,
|
|
|
|
gender: statistic_profile.str_gender,
|
|
|
|
age: statistic_profile.age,
|
|
|
|
group: statistic_profile.group ? statistic_profile.group.slug : nil
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|