1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-19 13:54:25 +01:00

(wip) report store statistics in UI

This commit is contained in:
Sylvain 2022-10-11 17:23:45 +02:00
parent 70f7ef8951
commit d9e8d0e40d
20 changed files with 121 additions and 104 deletions

View File

@ -9,7 +9,7 @@ class API::StatisticsController < API::ApiController
@statistics = StatisticIndex.all
end
%w[account event machine project subscription training user space].each do |path|
%w[account event machine project subscription training user space order].each do |path|
class_eval %{
def #{path}
authorize :statistic, :#{path}?
@ -30,11 +30,7 @@ class API::StatisticsController < API::ApiController
# return result
render json: results
end
}, __FILE__, __LINE__ - 20
end
%w[account event machine project subscription training user space].each do |path|
class_eval %{
def export_#{path}
authorize :statistic, :export_#{path}?
@ -56,7 +52,7 @@ class API::StatisticsController < API::ApiController
disposition: 'attachment'
end
end
}, __FILE__, __LINE__ - 22
}, __FILE__, __LINE__ - 42
end
def export_global

View File

@ -15,22 +15,23 @@ class Reservation < ApplicationRecord
accepts_nested_attributes_for :slots_reservations, allow_destroy: true
belongs_to :reservable, polymorphic: true
has_many :tickets
has_many :tickets, dependent: :destroy
accepts_nested_attributes_for :tickets, allow_destroy: false
has_many :invoice_items, as: :object, dependent: :destroy
has_one :payment_schedule_object, as: :object, dependent: :destroy
validates_presence_of :reservable_id, :reservable_type
validates :reservable_id, :reservable_type, presence: true
validate :machine_not_already_reserved, if: -> { reservable.is_a?(Machine) }
validate :training_not_fully_reserved, if: -> { reservable.is_a?(Training) }
validate :slots_not_locked
after_save :update_event_nb_free_places, if: proc { |reservation| reservation.reservable_type == 'Event' }
after_commit :notify_member_create_reservation, on: :create
after_commit :notify_admin_member_create_reservation, on: :create
after_commit :extend_subscription, on: :create
after_save :update_event_nb_free_places, if: proc { |reservation| reservation.reservable_type == 'Event' }
delegate :user, to: :statistic_profile
# @param canceled if true, count the number of seats for this reservation, including canceled seats
def total_booked_seats(canceled: false)
@ -50,10 +51,6 @@ class Reservation < ApplicationRecord
total
end
def user
statistic_profile.user
end
def update_event_nb_free_places
return unless reservable_type == 'Event'
@ -83,11 +80,11 @@ class Reservation < ApplicationRecord
daily_slots[1..].each do |slot|
found = false
result[date].each do |group_start, group_slots|
if slot[:start_at] === group_slots.last[:end_at]
result[date][group_start].push(slot)
found = true
break
end
next unless slot[:start_at] == group_slots.last[:end_at]
result[date][group_start].push(slot)
found = true
break
end
result[date][slot[:start_at]] = [slot] unless found
end

View File

@ -1,6 +1,7 @@
module Stats
class Account
include Elasticsearch::Persistence::Model
include StatConcern
end
# frozen_string_literal: true
# This is a statistical data saved in ElasticSearch, about an account creation
class Stats::Account
include Elasticsearch::Persistence::Model
include StatConcern
end

View File

@ -1,12 +1,13 @@
module Stats
class Event
include Elasticsearch::Persistence::Model
include StatConcern
include StatReservationConcern
# frozen_string_literal: true
attribute :eventId, Integer
attribute :eventDate, String
attribute :ageRange, String
attribute :eventTheme, String
end
# This is a statistical data saved in ElasticSearch, about an event reservation
class Stats::Event
include Elasticsearch::Persistence::Model
include StatConcern
include StatReservationConcern
attribute :eventId, Integer
attribute :eventDate, String
attribute :ageRange, String
attribute :eventTheme, String
end

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true
class Stats::StoreOrder
# This is a statistical data saved in ElasticSearch, about a store's order
class Stats::Order
include Elasticsearch::Persistence::Model
include StatConcern

View File

@ -1,14 +1,15 @@
module Stats
class Project
include Elasticsearch::Persistence::Model
include StatConcern
# frozen_string_literal: true
attribute :projectId, Integer
attribute :name, String
attribute :licence, Hash
attribute :themes, Array
attribute :components, Array
attribute :machines, Array
attribute :users, Integer
end
# This is a statistical data saved in ElasticSearch, about a project publication
class Stats::Project
include Elasticsearch::Persistence::Model
include StatConcern
attribute :projectId, Integer
attribute :name, String
attribute :licence, Hash
attribute :themes, Array
attribute :components, Array
attribute :machines, Array
attribute :users, Integer
end

View File

@ -1,9 +1,10 @@
module Stats
class Space
include Elasticsearch::Persistence::Model
include StatConcern
include StatReservationConcern
# frozen_string_literal: true
attribute :spaceId, Integer
end
# This is a statistical data saved in ElasticSearch, about a space reservation
class Stats::Space
include Elasticsearch::Persistence::Model
include StatConcern
include StatReservationConcern
attribute :spaceId, Integer
end

View File

@ -1,12 +1,13 @@
module Stats
class Subscription
include Elasticsearch::Persistence::Model
include StatConcern
# frozen_string_literal: true
attribute :ca, Float
attribute :planId, Integer
attribute :subscriptionId, Integer
attribute :invoiceItemId, Integer
attribute :groupName, String
end
# This is a statistical data saved in ElasticSearch, about a subscription to a plan
class Stats::Subscription
include Elasticsearch::Persistence::Model
include StatConcern
attribute :ca, Float
attribute :planId, Integer
attribute :subscriptionId, Integer
attribute :invoiceItemId, Integer
attribute :groupName, String
end

View File

@ -1,10 +1,11 @@
module Stats
class Training
include Elasticsearch::Persistence::Model
include StatConcern
include StatReservationConcern
# frozen_string_literal: true
attribute :trainingId, Integer
attribute :trainingDate, String
end
# This is a statistical data saved in ElasticSearch, about a training reservation
class Stats::Training
include Elasticsearch::Persistence::Model
include StatConcern
include StatReservationConcern
attribute :trainingId, Integer
attribute :trainingDate, String
end

View File

@ -1,6 +1,7 @@
module Stats
class User
include Elasticsearch::Persistence::Model
include StatConcern
end
# frozen_string_literal: true
# This is a statistical data saved in ElasticSearch, about revenue generated per user
class Stats::User
include Elasticsearch::Persistence::Model
include StatConcern
end

View File

@ -8,11 +8,11 @@ class Subscription < ApplicationRecord
belongs_to :statistic_profile
has_one :payment_schedule_object, as: :object, dependent: :destroy
has_one :payment_gateway_object, as: :item
has_one :payment_gateway_object, as: :item, dependent: :destroy
has_many :invoice_items, as: :object, dependent: :destroy
has_many :offer_days, dependent: :destroy
validates_presence_of :plan_id
validates :plan_id, presence: true
validates_with SubscriptionGroupValidator
# creation
@ -21,18 +21,21 @@ class Subscription < ApplicationRecord
after_save :notify_admin_subscribed_plan
after_save :notify_partner_subscribed_plan, if: :of_partner_plan?
delegate :user, to: :statistic_profile
def generate_and_save_invoice(operator_profile_id)
generate_invoice(operator_profile_id).save
end
def expire(time)
if !expired?
update_columns(expiration_date: time, canceled_at: time)
if expired?
false
else
# TODO, check if the rubocop:disable directove can be deleted
update_columns(expiration_date: time, canceled_at: time) # rubocop:disable Rails/SkipsModelValidations
notify_admin_subscription_canceled
notify_member_subscription_canceled
true
else
false
end
end
@ -47,10 +50,6 @@ class Subscription < ApplicationRecord
expiration_date
end
def user
statistic_profile.user
end
def original_payment_schedule
payment_schedule_object&.payment_schedule
end

View File

@ -1,6 +1,9 @@
# frozen_string_literal: true
# Check the access policies for API::StatisticsController
class StatisticPolicy < ApplicationPolicy
%w(index account event machine project subscription training user space scroll export_subscription export_machine
export_training export_event export_account export_project export_space export_global).each do |action|
%w[index account event machine project subscription training user space order scroll export_subscription export_machine
export_training export_event export_account export_project export_space export_order export_global].each do |action|
define_method "#{action}?" do
user.admin?
end

View File

@ -42,6 +42,10 @@ class Orders::OrderService
else
nil
end
# update in elasticsearch (statistics)
stat_order = Stats::Order.search(query: { term: { orderId: order.id } })
stat_order.map { |s| s.update(state: state) }
end
def in_stock?(order, stock_type = 'external')

View File

@ -9,15 +9,15 @@ class Statistics::Builders::StoreOrdersBuilderService
def build(options = default_options)
# project list
Statistics::FetcherService.store_orders_list(options).each do |o|
Stats::StoreOrder.create({ date: format_date(o[:date]),
type: 'order',
subType: 'store',
ca: o[:ca],
products: o[:order_products],
categories: o[:order_categories],
orderId: o[:order_id],
orderState: o[:order_state],
stat: 1 }.merge(user_info_stat(o)))
Stats::Order.create({ date: format_date(o[:date]),
type: 'order',
subType: 'store',
ca: o[:ca],
products: o[:order_products],
categories: o[:order_categories],
orderId: o[:order_id],
state: o[:order_state],
stat: 1 }.merge(user_info_stat(o)))
end
end
end

View File

@ -7,7 +7,7 @@ class Statistics::CleanerService
class << self
def clean_stat(options = default_options)
client = Elasticsearch::Model.client
%w[Account Event Machine Project Subscription Training User Space].each do |o|
%w[Account Event Machine Project Subscription Training User Space Order].each do |o|
model = "Stats::#{o}".constantize
client.delete_by_query(
index: model.index_name,

View File

@ -186,9 +186,9 @@ class Statistics::FetcherService
def store_orders_list(options = default_options)
result = []
Order.includes(order_items: [:orderable])
.joins(:order_items)
.joins(:order_items, :order_activities)
.where("order_items.orderable_type = 'Product'")
.where('orders.created_at >= :start_date AND orders.created_at <= :end_date', options)
.where('order_activities.created_at >= :start_date AND order_activities.created_at <= :end_date', options)
.each do |o|
result.push({ date: o.created_at.to_date, ca: calcul_ca(o.invoice) }
.merge(user_info(o.statistic_profile))

View File

@ -430,6 +430,7 @@ en:
subscriptions: "Subscriptions"
machines_hours: "Machines slots"
spaces: "Spaces"
orders: "Orders"
trainings: "Trainings"
events: "Events"
registrations: "Registrations"
@ -453,6 +454,7 @@ en:
account_creation: "Account creation"
project_publication: "Project publication"
duration: "Duration"
store: "Boutique"
#statistics exports to the Excel file format
export:
entries: "Entries"

View File

@ -282,7 +282,7 @@ Rails.application.routes.draw do
end
end
%w[account event machine project subscription training user space].each do |path|
%w[account event machine project subscription training user space order].each do |path|
post "/stats/#{path}/_search", to: "api/statistics##{path}"
post "/stats/#{path}/export", to: "api/statistics#export_#{path}"
end

View File

@ -1027,6 +1027,14 @@ unless StatisticIndex.find_by(es_type_key: 'space')
])
end
unless StatisticIndex.find_by(es_type_key: 'order')
index = StatisticIndex.create!(es_type_key: 'order', label: I18n.t('statistics.orders'))
StatisticType.create!([
{ statistic_index_id: index.id, key: 'store', label: I18n.t('statistics.store'),
graph: true, simple: true }
])
end
ProfileCustomField.find_or_create_by(label: 'N° SIRET')
ProfileCustomField.find_or_create_by(label: 'Code NAF')
ProfileCustomField.find_or_create_by(label: 'N° TVA intracommunautaire')

View File

@ -12,11 +12,11 @@ class StoreStatisticServiceTest < ActionDispatch::IntegrationTest
::Statistics::BuilderService.generate_statistic({ start_date: DateTime.current.beginning_of_day,
end_date: DateTime.current.end_of_day })
Stats::StoreOrder.refresh_index!
Stats::Order.refresh_index!
# we should find order id 15 (created today)
stat_order = Stats::StoreOrder.search(query: { bool: { must: [{ term: { date: DateTime.current.to_date.iso8601 } },
{ term: { type: 'order' } }] } }).first
stat_order = Stats::Order.search(query: { bool: { must: [{ term: { date: DateTime.current.to_date.iso8601 } },
{ term: { type: 'order' } }] } }).first
assert_not_nil stat_order
assert_equal @order.id, stat_order['orderId']
check_statistics_on_user(stat_order)