• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sleede / fab-manager / #97

pending completion
#97

push

coveralls-ruby

sylvainbx
Merge branch 'dev' for release 5.6.10

29 of 29 new or added lines in 5 files covered. (100.0%)

6833 of 11485 relevant lines covered (59.49%)

13.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.79
/app/services/statistics/fetcher_service.rb
1
# frozen_string_literal: true
2

3
# Fetch data from the PostgreSQL database and prepare them
4
# to be used in the statistics generation
5
class Statistics::FetcherService
1✔
6
  include Statistics::Concerns::HelpersConcern
1✔
7
  include Statistics::Concerns::ComputeConcern
1✔
8
  include Statistics::Concerns::ProjectsConcern
1✔
9
  include Statistics::Concerns::StoreOrdersConcern
1✔
10

11
  class << self
1✔
12
    def subscriptions_list(options = default_options)
1✔
13
      result = []
10✔
14
      InvoiceItem.where("object_type = '#{Subscription.name}' AND invoice_items.created_at >= :start_date " \
10✔
15
                        'AND invoice_items.created_at <= :end_date', options)
16
                 .eager_load(invoice: [:coupon]).find_each do |i|
17
        next if i.invoice.is_a?(Avoir)
6✔
18

19
        sub = i.object
6✔
20

21
        ca = i.amount.to_i
6✔
22
        cs = CouponService.new
6✔
23
        ca = cs.ventilate(cs.invoice_total_no_coupon(i.invoice), ca, i.invoice.coupon) unless i.invoice.coupon_id.nil?
6✔
24
        ca /= 100.00
6✔
25
        profile = sub.statistic_profile
6✔
26
        p = sub.plan
6✔
27
        result.push({ date: i.created_at.to_date,
6✔
28
                      plan: p.group.slug,
29
                      plan_id: p.id,
30
                      plan_interval: p.interval,
31
                      plan_interval_count: p.interval_count,
32
                      plan_group_name: p.group.name,
33
                      slug: p.slug,
34
                      duration: p.find_statistic_type.key,
35
                      subscription_id: sub.id,
36
                      invoice_item_id: i.id,
37
                      ca: ca }.merge(user_info(profile)))
38
      end
39
      result
10✔
40
    end
41

42
    # @param options [Hash]
43
    # @yield [reservation]
44
    # @yieldparam [Hash]
45
    def each_machine_reservation(options = default_options)
1✔
46
      Reservation
5✔
47
        .where("reservable_type = 'Machine' AND slots_reservations.canceled_at IS NULL AND " \
48
               'reservations.created_at >= :start_date AND reservations.created_at <= :end_date', options)
49
        .eager_load(:slots, :slots_reservations, :invoice_items, statistic_profile: [:group])
50
        .find_each do |r|
51
        next unless r.reservable
4✔
52

53
        profile = r.statistic_profile
4✔
54
        result = { date: r.created_at.to_date,
4✔
55
                   reservation_id: r.id,
56
                   machine_id: r.reservable.id,
57
                   machine_type: r.reservable.friendly_id,
58
                   machine_name: r.reservable.name,
59
                   slot_dates: r.slots.map(&:start_at).map(&:to_date),
60
                   nb_hours: (r.slots.map(&:duration).map(&:to_i).reduce(:+) / 3600.0).to_i,
4✔
61
                   ca: calcul_ca(r.original_invoice) }.merge(user_info(profile))
62
        yield result
4✔
63
      end
64
    end
65

66
    # @param options [Hash]
67
    # @yield [reservation]
68
    # @yieldparam [Hash]
69
    def each_space_reservation(options = default_options)
1✔
70
      Reservation
5✔
71
        .where("reservable_type = 'Space' AND slots_reservations.canceled_at IS NULL AND " \
72
               'reservations.created_at >= :start_date AND reservations.created_at <= :end_date', options)
73
        .eager_load(:slots, :slots_reservations, :invoice_items, statistic_profile: [:group])
74
        .find_each do |r|
75
        next unless r.reservable
×
76

77
        profile = r.statistic_profile
×
78
        result = { date: r.created_at.to_date,
×
79
                   reservation_id: r.id,
80
                   space_id: r.reservable.id,
81
                   space_name: r.reservable.name,
82
                   space_type: r.reservable.slug,
83
                   slot_dates: r.slots.map(&:start_at).map(&:to_date),
84
                   nb_hours: (r.slots.map(&:duration).map(&:to_i).reduce(:+) / 3600.0).to_i,
×
85
                   ca: calcul_ca(r.original_invoice) }.merge(user_info(profile))
86
        yield result
×
87
      end
88
    end
89

90
    # @param options [Hash]
91
    # @yield [reservation]
92
    # @yieldparam [Hash]
93
    def each_training_reservation(options = default_options)
1✔
94
      Reservation
5✔
95
        .where("reservable_type = 'Training' AND slots_reservations.canceled_at IS NULL AND " \
96
               'reservations.created_at >= :start_date AND reservations.created_at <= :end_date', options)
97
        .eager_load(:slots, :slots_reservations, :invoice_items, statistic_profile: [:group])
98
        .find_each do |r|
99
        next unless r.reservable
1✔
100

101
        profile = r.statistic_profile
1✔
102
        slot = r.slots.first
1✔
103
        result = { date: r.created_at.to_date,
1✔
104
                   reservation_id: r.id,
105
                   training_id: r.reservable.id,
106
                   training_type: r.reservable.friendly_id,
107
                   training_name: r.reservable.name,
108
                   training_date: slot.start_at.to_date,
109
                   nb_hours: difference_in_hours(slot.start_at, slot.end_at),
110
                   ca: calcul_ca(r.original_invoice) }.merge(user_info(profile))
111
        yield result
1✔
112
      end
113
    end
114

115
    # @param options [Hash]
116
    # @yield [reservation]
117
    # @yieldparam [Hash]
118
    def each_event_reservation(options = default_options)
1✔
119
      Reservation
5✔
120
        .where("reservable_type = 'Event' AND slots_reservations.canceled_at IS NULL AND " \
121
               'reservations.created_at >= :start_date AND reservations.created_at <= :end_date', options)
122
        .eager_load(:slots, :slots_reservations, :invoice_items, statistic_profile: [:group])
123
        .find_each do |r|
124
        next unless r.reservable
×
125

126
        profile = r.statistic_profile
×
127
        slot = r.slots.first
×
128
        result = { date: r.created_at.to_date,
×
129
                   reservation_id: r.id,
130
                   event_id: r.reservable.id,
131
                   event_type: r.reservable.category.slug,
132
                   event_name: r.reservable.name,
133
                   event_date: slot.start_at.to_date,
134
                   event_theme: (r.reservable.event_themes.first ? r.reservable.event_themes.first.name : ''),
×
135
                   age_range: (r.reservable.age_range_id ? r.reservable.age_range.name : ''),
×
136
                   nb_places: r.total_booked_seats,
137
                   nb_hours: difference_in_hours(slot.start_at, slot.end_at),
138
                   ca: calcul_ca(r.original_invoice) }.merge(user_info(profile))
139
        yield result
×
140
      end
141
    end
142

143
    def members_ca_list(options = default_options)
1✔
144
      subscriptions_ca_list = subscriptions_list(options)
5✔
145
      reservations_ca_list = []
5✔
146
      avoirs_ca_list = []
5✔
147
      users_list = []
5✔
148
      Reservation.where('reservations.created_at >= :start_date AND reservations.created_at <= :end_date', options)
5✔
149
                 .eager_load(:slots, :invoice_items, statistic_profile: [:group])
150
                 .find_each do |r|
151
        next unless r.reservable
5✔
152

153
        reservations_ca_list.push(
5✔
154
          { date: r.created_at.to_date, ca: calcul_ca(r.original_invoice) || 0 }.merge(user_info(r.statistic_profile))
155
        )
156
      end
157
      Avoir.where('invoices.created_at >= :start_date AND invoices.created_at <= :end_date', options)
5✔
158
           .eager_load(:invoice_items, statistic_profile: [:group])
159
           .find_each do |i|
160
        # the following line is a workaround for issue #196
161
        profile = i.statistic_profile || i.main_item.object&.wallet&.user&.statistic_profile
×
162
        avoirs_ca_list.push({ date: i.created_at.to_date, ca: calcul_avoir_ca(i) || 0 }.merge(user_info(profile)))
×
163
      end
164
      reservations_ca_list.concat(subscriptions_ca_list).concat(avoirs_ca_list).each do |e|
5✔
165
        profile = StatisticProfile.find(e[:statistic_profile_id])
8✔
166
        u = find_or_create_user_info(profile, users_list)
8✔
167
        u[:date] = e[:date]
8✔
168
        add_ca(u, e[:ca], users_list)
8✔
169
      end
170
      users_list
5✔
171
    end
172

173
    # @param options [Hash]
174
    # @yield [reservation]
175
    # @yieldparam [Hash]
176
    def each_member(options = default_options)
1✔
177
      member = Role.find_by(name: 'member')
5✔
178
      StatisticProfile.where('role_id = :member AND created_at >= :start_date AND created_at <= :end_date',
5✔
179
                             options.merge(member: member.id))
180
                      .find_each do |sp|
181
        next if sp.user&.need_completion?
×
182

183
        result = { date: sp.created_at.to_date }.merge(user_info(sp))
×
184
        yield result
×
185
      end
186
    end
187

188
    # @param options [Hash]
189
    # @yield [reservation]
190
    # @yieldparam [Hash]
191
    def each_project(options = default_options)
1✔
192
      Project.where('projects.published_at >= :start_date AND projects.published_at <= :end_date', options)
5✔
193
             .eager_load(:licence, :themes, :components, :machines, :project_users, author: [:group])
194
             .find_each do |p|
195
        result = { date: p.created_at.to_date }.merge(user_info(p.author)).merge(project_info(p))
×
196
        yield result
×
197
      end
198
    end
199

200
    # @param states [Array<String>]
201
    # @param options [Hash]
202
    # @yield [reservation]
203
    # @yieldparam [Hash]
204
    def each_store_order(states, options = default_options)
1✔
205
      Order.includes(order_items: [:orderable])
10✔
206
           .joins(:order_items, :order_activities)
207
           .where(order_items: { orderable_type: 'Product' })
208
           .where(orders: { state: states })
209
           .where('order_activities.created_at >= :start_date AND order_activities.created_at <= :end_date', options)
210
           .group('orders.id')
211
           .find_each do |o|
212
        result = { date: o.created_at.to_date, ca: calcul_ca(o.invoice) }
2✔
213
                 .merge(user_info(o.statistic_profile))
214
                 .merge(store_order_info(o))
215
        yield result
2✔
216
      end
217
    end
218

219
    private
1✔
220

221
    def add_ca(profile, new_ca, users_list)
1✔
222
      if profile[:ca]
8✔
223
        profile[:ca] += new_ca || 0
3✔
224
      else
225
        profile[:ca] = new_ca || 0
5✔
226
        users_list.push profile
5✔
227
      end
228
    end
229

230
    def find_or_create_user_info(profile, list)
1✔
231
      found = list.find do |l|
8✔
232
        l[:statistic_profile_id] == profile.id
5✔
233
      end
234
      found || user_info(profile)
8✔
235
    end
236

237
    def user_info(statistic_profile)
1✔
238
      return {} unless statistic_profile
23✔
239

240
      {
241
        statistic_profile_id: statistic_profile.id,
23✔
242
        user_id: statistic_profile.user_id,
243
        gender: statistic_profile.str_gender,
244
        age: statistic_profile.age,
245
        group: statistic_profile.group ? statistic_profile.group.slug : nil
23✔
246
      }
247
    end
248
  end
249
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc