mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-20 14:54:15 +01:00
(merge) Merge branch 'product-store_stats' into product-store
This commit is contained in:
commit
f80aec1ef2
@ -36,3 +36,5 @@ Style/FormatString:
|
||||
EnforcedStyle: sprintf
|
||||
Style/FormatStringToken:
|
||||
EnforcedStyle: template
|
||||
Rails/RedundantPresenceValidationOnBelongsTo:
|
||||
Enabled: false
|
||||
|
@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Space
|
||||
# API Controller for various statistical resources (gateway to elasticsearch DB)
|
||||
class API::StatisticsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
@ -9,49 +9,25 @@ 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}?
|
||||
def #{path} # def account
|
||||
authorize :statistic, :#{path}? # authorize :statistic, :account
|
||||
render json: Statistics::QueryService.query('#{path}', request) # render json: Statistics::QueryService.query('account', request)
|
||||
end # end
|
||||
|
||||
# remove additional parameters
|
||||
statistic_type = request.query_parameters.delete('stat-type')
|
||||
custom_query = request.query_parameters.delete('custom-query')
|
||||
start_date = request.query_parameters.delete('start-date')
|
||||
end_date = request.query_parameters.delete('end-date')
|
||||
def export_#{path} # def export_account
|
||||
authorize :statistic, :export_#{path}? # authorize :statistic, :export_account?
|
||||
|
||||
# run main query in elasticSearch
|
||||
query = MultiJson.load(request.body.read)
|
||||
results = Stats::#{path.classify}.search(query, request.query_parameters.symbolize_keys).response
|
||||
|
||||
# run additional custom aggregations, if any
|
||||
CustomAggregationService.new.("#{path}", statistic_type, start_date, end_date, custom_query, results)
|
||||
|
||||
# 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}?
|
||||
|
||||
export = Export.where(category:'statistics', export_type: '#{path}', query: params[:body], key: params[:type_key]).last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new(category:'statistics',
|
||||
export_type: '#{path}',
|
||||
user: current_user,
|
||||
query: params[:body],
|
||||
key: params[:type_key])
|
||||
@export = Statistics::QueryService.export('#{path}', params) # @export = Statistics::QueryService.export('account', params)
|
||||
if @export.is_a?(Export)
|
||||
if @export.save
|
||||
render json: {export_id: @export.id}, status: :ok
|
||||
render json: { export_id: @export.id }, status: :ok
|
||||
else
|
||||
render json: @export.errors, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
send_file File.join(Rails.root, export.file),
|
||||
send_file @export,
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
disposition: 'attachment'
|
||||
end
|
||||
@ -62,16 +38,15 @@ class API::StatisticsController < API::ApiController
|
||||
def export_global
|
||||
authorize :statistic, :export_global?
|
||||
|
||||
export = Export.where(category: 'statistics', export_type: 'global', query: params[:body]).last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new(category: 'statistics', export_type: 'global', user: current_user, query: params[:body])
|
||||
@export = Statistics::QueryService.export(global, params)
|
||||
if @export.is_a?(Export)
|
||||
if @export.save
|
||||
render json: { export_id: @export.id }, status: :ok
|
||||
else
|
||||
render json: @export.errors, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
send_file File.join(Rails.root, export.file),
|
||||
send_file @export,
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
disposition: 'attachment'
|
||||
end
|
||||
|
@ -18,7 +18,7 @@ class API::WalletController < API::ApiController
|
||||
end
|
||||
|
||||
def credit
|
||||
return head 422 unless Setting.get('wallet_module')
|
||||
return head :unprocessable_entity unless Setting.get('wallet_module')
|
||||
|
||||
@wallet = Wallet.find(credit_params[:id])
|
||||
authorize @wallet
|
||||
@ -28,7 +28,7 @@ class API::WalletController < API::ApiController
|
||||
service.create_avoir(transaction, credit_params[:avoir_date], credit_params[:avoir_description]) if credit_params[:avoir]
|
||||
render :show
|
||||
else
|
||||
head 422
|
||||
head :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -106,6 +106,7 @@ Application.Controllers.controller('HomeController', ['$scope', '$transition$',
|
||||
const setupWelcomeTour = function () {
|
||||
// get the tour defined by the ui-tour directive
|
||||
const uitour = uiTourService.getTourByName('welcome');
|
||||
if (!uitour) return;
|
||||
// add the steps
|
||||
uitour.createStep({
|
||||
selector: 'body',
|
||||
|
@ -7,7 +7,7 @@ class Order < PaymentDocument
|
||||
belongs_to :coupon
|
||||
belongs_to :invoice
|
||||
has_many :order_items, dependent: :destroy
|
||||
has_one :payment_gateway_object, as: :item
|
||||
has_one :payment_gateway_object, as: :item, dependent: :destroy
|
||||
has_many :order_activities, dependent: :destroy
|
||||
|
||||
ALL_STATES = %w[cart paid payment_failed refunded in_progress ready canceled delivered].freeze
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
13
app/models/stats/order.rb
Normal file
13
app/models/stats/order.rb
Normal file
@ -0,0 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# This is a statistical data saved in ElasticSearch, about a store's order
|
||||
class Stats::Order
|
||||
include Elasticsearch::Persistence::Model
|
||||
include StatConcern
|
||||
|
||||
attribute :orderId, Integer
|
||||
attribute :state, String
|
||||
attribute :products, Array
|
||||
attribute :categories, Array
|
||||
attribute :ca, Float
|
||||
end
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -11,6 +11,8 @@ class Wallet < ApplicationRecord
|
||||
|
||||
validates :invoicing_profile, presence: true
|
||||
|
||||
delegate :user, to: :invoicing_profile
|
||||
|
||||
def credit(amount)
|
||||
if amount.is_a?(Numeric) && amount >= 0
|
||||
self.amount += amount
|
||||
@ -26,8 +28,4 @@ class Wallet < ApplicationRecord
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
def user
|
||||
invoicing_profile.user
|
||||
end
|
||||
end
|
||||
|
@ -8,17 +8,15 @@ class WalletTransaction < ApplicationRecord
|
||||
belongs_to :wallet
|
||||
belongs_to :reservation
|
||||
# what was paid with the wallet
|
||||
has_one :invoice
|
||||
has_one :payment_schedule
|
||||
has_one :invoice, dependent: :nullify
|
||||
has_one :payment_schedule, dependent: :nullify
|
||||
# how the wallet was credited
|
||||
has_one :invoice_item, as: :object, dependent: :destroy
|
||||
|
||||
validates_inclusion_of :transaction_type, in: %w[credit debit]
|
||||
validates :transaction_type, inclusion: { in: %w[credit debit] }
|
||||
validates :invoicing_profile, :wallet, presence: true
|
||||
|
||||
def user
|
||||
invoicing_profile.user
|
||||
end
|
||||
delegate :user, to: :invoicing_profile
|
||||
|
||||
def original_invoice
|
||||
invoice_item.invoice
|
||||
|
@ -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
|
||||
|
@ -12,6 +12,8 @@ class ExportService
|
||||
last_export_reservations
|
||||
when 'users/subscription'
|
||||
last_export_subscriptions
|
||||
when %r{statistics/.*}
|
||||
last_export_statistics(type.split('/')[1])
|
||||
else
|
||||
raise TypeError "unknown export type: #{type}"
|
||||
end
|
||||
@ -44,5 +46,10 @@ class ExportService
|
||||
.where('created_at > ?', last_update)
|
||||
.last
|
||||
end
|
||||
|
||||
def last_export_statistics(type)
|
||||
Export.where(category: 'statistics', export_type: type, query: params[:body], key: params[:type_key])
|
||||
.last
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -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')
|
||||
|
@ -11,6 +11,7 @@ class Statistics::BuilderService
|
||||
Statistics::Builders::ReservationsBuilderService.build(options)
|
||||
Statistics::Builders::MembersBuilderService.build(options)
|
||||
Statistics::Builders::ProjectsBuilderService.build(options)
|
||||
Statistics::Builders::StoreOrdersBuilderService.build(options)
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -0,0 +1,30 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Generate statistics indicators about store's orders
|
||||
class Statistics::Builders::StoreOrdersBuilderService
|
||||
include Statistics::Concerns::HelpersConcern
|
||||
include Statistics::Concerns::StoreOrdersConcern
|
||||
|
||||
class << self
|
||||
def build(options = default_options)
|
||||
states = {
|
||||
'paid-processed': %w[paid in_progress ready delivered],
|
||||
aborted: %w[payment_failed refunded canceled]
|
||||
}
|
||||
# orders list
|
||||
states.each do |sub_type, order_states|
|
||||
Statistics::FetcherService.store_orders_list(order_states, options).each do |o|
|
||||
Stats::Order.create({ date: format_date(o[:date]),
|
||||
type: 'store',
|
||||
subType: sub_type,
|
||||
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
|
||||
end
|
||||
end
|
@ -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,
|
||||
|
32
app/services/statistics/concerns/store_orders_concern.rb
Normal file
32
app/services/statistics/concerns/store_orders_concern.rb
Normal file
@ -0,0 +1,32 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides methods to consolidate data from Store Orders to use in statistics
|
||||
module Statistics::Concerns::StoreOrdersConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
def get_order_products(order)
|
||||
order.order_items.where(orderable_type: 'Product').map do |item|
|
||||
{ id: item.orderable_id, name: item.orderable.name }
|
||||
end
|
||||
end
|
||||
|
||||
def get_order_categories(order)
|
||||
order.order_items
|
||||
.where(orderable_type: 'Product')
|
||||
.map(&:orderable)
|
||||
.map(&:product_category)
|
||||
.map { |cat| { id: cat.id, name: cat.name } }
|
||||
.uniq
|
||||
end
|
||||
|
||||
def store_order_info(order)
|
||||
{
|
||||
order_id: order.id,
|
||||
order_state: order.state,
|
||||
order_products: get_order_products(order),
|
||||
order_categories: get_order_categories(order)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
@ -6,6 +6,7 @@ class Statistics::FetcherService
|
||||
include Statistics::Concerns::HelpersConcern
|
||||
include Statistics::Concerns::ComputeConcern
|
||||
include Statistics::Concerns::ProjectsConcern
|
||||
include Statistics::Concerns::StoreOrdersConcern
|
||||
|
||||
class << self
|
||||
def subscriptions_list(options = default_options)
|
||||
@ -182,6 +183,22 @@ class Statistics::FetcherService
|
||||
result
|
||||
end
|
||||
|
||||
def store_orders_list(states, options = default_options)
|
||||
result = []
|
||||
Order.includes(order_items: [:orderable])
|
||||
.joins(:order_items, :order_activities)
|
||||
.where(order_items: { orderable_type: 'Product' })
|
||||
.where(orders: { state: states })
|
||||
.where('order_activities.created_at >= :start_date AND order_activities.created_at <= :end_date', options)
|
||||
.group('orders.id')
|
||||
.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
|
||||
|
||||
private
|
||||
|
||||
def add_ca(profile, new_ca, users_list)
|
||||
|
37
app/services/statistics/query_service.rb
Normal file
37
app/services/statistics/query_service.rb
Normal file
@ -0,0 +1,37 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Query the elasticsearch database of statistics and format the result
|
||||
class Statistics::QueryService
|
||||
class << self
|
||||
def query(statistic_index, request)
|
||||
# remove additional parameters
|
||||
statistic_type = request.query_parameters.delete('stat-type')
|
||||
custom_query = request.query_parameters.delete('custom-query')
|
||||
start_date = request.query_parameters.delete('start-date')
|
||||
end_date = request.query_parameters.delete('end-date')
|
||||
|
||||
# run main query in elasticSearch
|
||||
query = MultiJson.load(request.body.read)
|
||||
model = "Stats::#{statistic_index}".constantize
|
||||
results = model.search(query, request.query_parameters.symbolize_keys).response
|
||||
|
||||
# run additional custom aggregations, if any
|
||||
CustomAggregationService.new.call(statistic_index, statistic_type, start_date, end_date, custom_query, results)
|
||||
|
||||
results
|
||||
end
|
||||
|
||||
def export(statistic_index, params)
|
||||
export = ExportService.last_export("statistics/#{statistic_index}")
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
Export.new(category: 'statistics',
|
||||
export_type: statistic_index,
|
||||
user: current_user,
|
||||
query: params[:body],
|
||||
key: params[:type_key])
|
||||
else
|
||||
File.root.join(export.file)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -9,33 +9,33 @@ class WalletService
|
||||
|
||||
## credit an amount to wallet, if credit success then return a wallet transaction and notify to admin
|
||||
def credit(amount)
|
||||
transaction = nil
|
||||
ActiveRecord::Base.transaction do
|
||||
if @wallet.credit(amount)
|
||||
if @wallet&.credit(amount)
|
||||
transaction = WalletTransaction.new(
|
||||
invoicing_profile: @user.invoicing_profile,
|
||||
invoicing_profile: @user&.invoicing_profile,
|
||||
wallet: @wallet,
|
||||
transaction_type: 'credit',
|
||||
amount: amount
|
||||
)
|
||||
if transaction.save
|
||||
NotificationCenter.call type: 'notify_user_wallet_is_credited',
|
||||
receiver: @wallet.user,
|
||||
attached_object: transaction
|
||||
NotificationCenter.call type: 'notify_admin_user_wallet_is_credited',
|
||||
receiver: User.admins_and_managers,
|
||||
attached_object: transaction
|
||||
transaction
|
||||
end
|
||||
raise ActiveRecord::Rollback unless transaction.save
|
||||
|
||||
NotificationCenter.call type: 'notify_user_wallet_is_credited',
|
||||
receiver: @wallet&.user,
|
||||
attached_object: transaction
|
||||
NotificationCenter.call type: 'notify_admin_user_wallet_is_credited',
|
||||
receiver: User.admins_and_managers,
|
||||
attached_object: transaction
|
||||
end
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
false
|
||||
transaction
|
||||
end
|
||||
|
||||
## debit an amount to wallet, if debit success then return a wallet transaction
|
||||
def debit(amount)
|
||||
transaction = nil
|
||||
ActiveRecord::Base.transaction do
|
||||
if @wallet.debit(amount)
|
||||
if @wallet&.debit(amount)
|
||||
transaction = WalletTransaction.new(
|
||||
invoicing_profile: @user&.invoicing_profile,
|
||||
wallet: @wallet,
|
||||
@ -43,11 +43,10 @@ class WalletService
|
||||
amount: amount
|
||||
)
|
||||
|
||||
transaction if transaction.save
|
||||
raise ActiveRecord::Rollback unless transaction.save
|
||||
end
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
false
|
||||
transaction
|
||||
end
|
||||
|
||||
## create a refund invoice associated with the given wallet transaction
|
||||
|
@ -1258,6 +1258,7 @@ en:
|
||||
export_is_running_you_ll_be_notified_when_its_ready: "Export is running. You'll be notified when it's ready."
|
||||
create_plans_to_start: "Start by creating new subscription plans."
|
||||
click_here: "Click here to create your first one."
|
||||
average_cart: "Average cart:"
|
||||
#statistics graphs
|
||||
stats_graphs:
|
||||
statistics: "Statistics"
|
||||
|
@ -430,6 +430,7 @@ en:
|
||||
subscriptions: "Subscriptions"
|
||||
machines_hours: "Machines slots"
|
||||
spaces: "Spaces"
|
||||
orders: "Orders"
|
||||
trainings: "Trainings"
|
||||
events: "Events"
|
||||
registrations: "Registrations"
|
||||
@ -453,6 +454,9 @@ en:
|
||||
account_creation: "Account creation"
|
||||
project_publication: "Project publication"
|
||||
duration: "Duration"
|
||||
store: "Boutique"
|
||||
paid-processed: "Paid and/or processed"
|
||||
aborted: "Aborted"
|
||||
#statistics exports to the Excel file format
|
||||
export:
|
||||
entries: "Entries"
|
||||
|
@ -283,7 +283,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
|
||||
|
24
db/seeds.rb
24
db/seeds.rb
@ -1027,6 +1027,30 @@ 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'))
|
||||
type = StatisticType.create!([
|
||||
{ statistic_index_id: index.id, key: 'store', label: I18n.t('statistics.store'),
|
||||
graph: true, simple: true }
|
||||
])
|
||||
StatisticSubType.create!([
|
||||
{ key: 'paid-processed', label: I18n.t('statistics.paid-processed'), statistic_types: [type] },
|
||||
{ key: 'aborted', label: I18n.t('statistics.aborted'), statistic_types: [type] }
|
||||
])
|
||||
|
||||
# average cart price for orders
|
||||
average_cart = StatisticCustomAggregation.new(
|
||||
statistic_type_id: type.id,
|
||||
es_index: 'stats',
|
||||
es_type: 'order',
|
||||
field: 'average_cart',
|
||||
query: '{"size":0, "aggregations":{"%{aggs_name}":{"avg":{"field":"ca", ' \
|
||||
'"script":"BigDecimal.valueOf(_value).setScale(1, RoundingMode.HALF_UP)", "missing": 0}}}, ' \
|
||||
'"query":{"bool":{"must":[{"range": {"date":{"gte":"%{start_date}", "lte":"%{end_date}"}}}]}}}'
|
||||
)
|
||||
average_cart.save!
|
||||
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')
|
||||
|
100
test/fixtures/assets.yml
vendored
100
test/fixtures/assets.yml
vendored
@ -70,3 +70,103 @@ asset_8:
|
||||
type: UserAvatar
|
||||
created_at: 2018-12-27 14:48:52.141382000 Z
|
||||
updated_at: 2018-12-27 14:48:52.141382000 Z
|
||||
|
||||
asset_2707:
|
||||
id: 2707
|
||||
viewable_id: 3
|
||||
viewable_type: Product
|
||||
attachment: appset-icon.png
|
||||
type: ProductImage
|
||||
created_at: '2022-09-13 10:05:07.212923'
|
||||
updated_at: '2022-09-27 10:17:51.976313'
|
||||
is_main: true
|
||||
asset_2729:
|
||||
id: 2729
|
||||
viewable_id: 16
|
||||
viewable_type: Product
|
||||
attachment: osb.jpeg
|
||||
type: ProductImage
|
||||
created_at: '2022-09-14 13:50:12.588896'
|
||||
updated_at: '2022-09-27 10:13:39.414052'
|
||||
is_main: true
|
||||
asset_2727:
|
||||
id: 2727
|
||||
viewable_id: 15
|
||||
viewable_type: Product
|
||||
attachment: cp.jpeg
|
||||
type: ProductImage
|
||||
created_at: '2022-09-14 13:49:08.237136'
|
||||
updated_at: '2022-09-27 10:13:51.282923'
|
||||
is_main: true
|
||||
asset_2721:
|
||||
id: 2721
|
||||
viewable_id: 12
|
||||
viewable_type: Product
|
||||
attachment: casqueapointe.jpg
|
||||
type: ProductImage
|
||||
created_at: '2022-09-14 13:42:36.731315'
|
||||
updated_at: '2022-09-27 10:14:23.371827'
|
||||
is_main: true
|
||||
asset_2731:
|
||||
id: 2731
|
||||
viewable_id: 17
|
||||
viewable_type: Product
|
||||
attachment: 3plis.jpeg
|
||||
type: ProductImage
|
||||
created_at: '2022-09-14 13:51:12.634244'
|
||||
updated_at: '2022-09-27 10:13:28.657539'
|
||||
is_main: true
|
||||
asset_2725:
|
||||
id: 2725
|
||||
viewable_id: 14
|
||||
viewable_type: Product
|
||||
attachment: melamine.jpeg
|
||||
type: ProductImage
|
||||
created_at: '2022-09-14 13:48:05.033284'
|
||||
updated_at: '2022-09-27 10:14:00.569077'
|
||||
is_main: true
|
||||
asset_2723:
|
||||
id: 2723
|
||||
viewable_id: 13
|
||||
viewable_type: Product
|
||||
attachment: mdf.jpeg
|
||||
type: ProductImage
|
||||
created_at: '2022-09-14 13:47:18.129274'
|
||||
updated_at: '2022-09-27 10:14:10.137542'
|
||||
is_main: true
|
||||
asset_2733:
|
||||
id: 2733
|
||||
viewable_id: 18
|
||||
viewable_type: Product
|
||||
attachment: lamelle-colle.jpeg
|
||||
type: ProductImage
|
||||
created_at: '2022-09-14 13:52:08.666869'
|
||||
updated_at: '2022-09-27 10:13:10.979122'
|
||||
is_main: true
|
||||
asset_2719:
|
||||
id: 2719
|
||||
viewable_id: 11
|
||||
viewable_type: Product
|
||||
attachment: bulldozer.png
|
||||
type: ProductImage
|
||||
created_at: '2022-09-14 13:41:16.209363'
|
||||
updated_at: '2022-09-27 10:14:33.153221'
|
||||
is_main: true
|
||||
asset_2743:
|
||||
id: 2743
|
||||
viewable_id: 22
|
||||
viewable_type: Product
|
||||
attachment: filament_pla_1_75_bleu.jpeg
|
||||
type: ProductImage
|
||||
created_at: '2022-10-03 14:00:50.082820'
|
||||
updated_at: '2022-10-03 14:00:50.082820'
|
||||
is_main: true
|
||||
asset_2744:
|
||||
id: 2744
|
||||
viewable_id: 23
|
||||
viewable_type: Product
|
||||
attachment: filament-pla_blanc.webp
|
||||
type: ProductImage
|
||||
created_at: '2022-10-03 14:01:43.711513'
|
||||
updated_at: '2022-10-03 14:01:43.711513'
|
||||
is_main: true
|
||||
|
156
test/fixtures/invoice_items.yml
vendored
156
test/fixtures/invoice_items.yml
vendored
@ -72,3 +72,159 @@ invoice_item_6:
|
||||
object_type: Subscription
|
||||
object_id: 4
|
||||
main: true
|
||||
invoice_item_11702:
|
||||
id: 11702
|
||||
invoice_id: 5811
|
||||
amount: 4000
|
||||
created_at: '2022-09-20 15:14:23.015625'
|
||||
updated_at: '2022-09-20 15:14:23.180166'
|
||||
description: Tablette lamellé-collé x 1
|
||||
invoice_item_id:
|
||||
footprint: 1d112a787e89d444f2817b909d7857a3a26fc2a3cd4c4404fb50bec282988a02
|
||||
object_type: OrderItem
|
||||
object_id: 1
|
||||
main: true
|
||||
invoice_item_11703:
|
||||
id: 11703
|
||||
invoice_id: 5811
|
||||
amount: 500
|
||||
created_at: '2022-09-20 15:14:23.287522'
|
||||
updated_at: '2022-09-20 15:14:23.289957'
|
||||
description: Panneaux de MDF x 1
|
||||
invoice_item_id:
|
||||
footprint: 67f143564abfeab7cb93988a02987a5a2b04a2632d0f9cfde61fa39c398cd02b
|
||||
object_type: OrderItem
|
||||
object_id: 2
|
||||
main: false
|
||||
invoice_item_11704:
|
||||
id: 11704
|
||||
invoice_id: 5812
|
||||
amount: 6000
|
||||
created_at: '2022-09-20 15:14:48.367843'
|
||||
updated_at: '2022-09-20 15:14:48.385139'
|
||||
description: Panneau de contre-plaqué x 4
|
||||
invoice_item_id:
|
||||
footprint: ea51c614632c018f0fae53c2bf8503c71d18c082ae3246155971e19ac2db143a
|
||||
object_type: OrderItem
|
||||
object_id: 3
|
||||
main: true
|
||||
invoice_item_11712:
|
||||
id: 11712
|
||||
invoice_id: 5816
|
||||
amount: 119
|
||||
created_at: '2022-10-04 12:36:03.103560'
|
||||
updated_at: '2022-10-04 12:36:03.282529'
|
||||
description: Filament PLA blanc x 1
|
||||
invoice_item_id:
|
||||
footprint: 4c5c8a1d7884502ea7791aeed1701cf3761562855d51ed19396b344c665c308b
|
||||
object_type: OrderItem
|
||||
object_id: 16
|
||||
main: true
|
||||
invoice_item_11713:
|
||||
id: 11713
|
||||
invoice_id: 5816
|
||||
amount: 200
|
||||
created_at: '2022-10-04 12:36:03.286776'
|
||||
updated_at: '2022-10-04 12:36:03.290235'
|
||||
description: Filament PLA bleu x 1
|
||||
invoice_item_id:
|
||||
footprint: 12c1a2c7fdb0f4b35d0c24137e6e0bdbbb39fa5c6500aa7837c67f92084d5071
|
||||
object_type: OrderItem
|
||||
object_id: 17
|
||||
main: false
|
||||
invoice_item_11714:
|
||||
id: 11714
|
||||
invoice_id: 5817
|
||||
amount: 119
|
||||
created_at: '2022-10-04 13:54:42.977460'
|
||||
updated_at: '2022-10-04 13:54:42.992564'
|
||||
description: Filament PLA blanc x 1
|
||||
invoice_item_id:
|
||||
footprint: cdb07fe1f0b986b9a53b6ec71f91a96e8b8d438592e88fd0041133b2ab46c8ca
|
||||
object_type: OrderItem
|
||||
object_id: 18
|
||||
main: true
|
||||
invoice_item_11715:
|
||||
id: 11715
|
||||
invoice_id: 5817
|
||||
amount: 1500
|
||||
created_at: '2022-10-04 13:54:43.021426'
|
||||
updated_at: '2022-10-04 13:54:43.024326'
|
||||
description: Panneau de contre-plaqué x 1
|
||||
invoice_item_id:
|
||||
footprint: 3ac08745b737bc370424ee9f1b68b421000eb98e0f3e65d7395d905d75de05c6
|
||||
object_type: OrderItem
|
||||
object_id: 19
|
||||
main: false
|
||||
invoice_item_11716:
|
||||
id: 11716
|
||||
invoice_id: 5818
|
||||
amount: 1000
|
||||
created_at: '2022-10-04 14:04:12.745449'
|
||||
updated_at: '2022-10-04 14:04:12.749266'
|
||||
description: Bulldozer x 1
|
||||
invoice_item_id:
|
||||
footprint: 1f4b6489579d7f045c846b97bc8ed402ec91f6fd7a5c2fa93b74eb7d21c7de39
|
||||
object_type: OrderItem
|
||||
object_id: 20
|
||||
main: true
|
||||
invoice_item_11717:
|
||||
id: 11717
|
||||
invoice_id: 5819
|
||||
amount: 2
|
||||
created_at: '2022-10-04 14:17:52.856695'
|
||||
updated_at: '2022-10-04 14:17:52.871262'
|
||||
description: Sticker Hello x 2
|
||||
invoice_item_id:
|
||||
footprint: 0fbecff886d9c2ffc332def13fa2c8869be8a40d2be7a3126a77974bd920c563
|
||||
object_type: OrderItem
|
||||
object_id: 21
|
||||
main: true
|
||||
invoice_item_11718:
|
||||
id: 11718
|
||||
invoice_id: 5819
|
||||
amount: 4000
|
||||
created_at: '2022-10-04 14:17:52.875854'
|
||||
updated_at: '2022-10-04 14:17:52.878780'
|
||||
description: Tablette lamellé-collé x 1
|
||||
invoice_item_id:
|
||||
footprint: ad160b9357518b31f63661fe38998b8c1d97fda61bc744876826ae638a8142a0
|
||||
object_type: OrderItem
|
||||
object_id: 22
|
||||
main: false
|
||||
invoice_item_11719:
|
||||
id: 11719
|
||||
invoice_id: 5820
|
||||
amount: 12000
|
||||
created_at: '2022-10-04 14:25:37.319701'
|
||||
updated_at: '2022-10-04 14:25:37.322782'
|
||||
description: Tablette lamellé-collé x 3
|
||||
invoice_item_id:
|
||||
footprint: 409a6f0b9f67510038a8b9a407db6d09b97f12d7169d6f6f121eedb2941d1bfc
|
||||
object_type: OrderItem
|
||||
object_id: 11
|
||||
main: true
|
||||
invoice_item_11720:
|
||||
id: 11720
|
||||
invoice_id: 5821
|
||||
amount: 12000
|
||||
created_at: '2022-10-04 14:32:28.209257'
|
||||
updated_at: '2022-10-04 14:32:28.226556'
|
||||
description: Tablette lamellé-collé x 3
|
||||
invoice_item_id:
|
||||
footprint: 733610b9c8e33f6a63f497d867d40386c623f12a526814d09d88a96f53741b7b
|
||||
object_type: OrderItem
|
||||
object_id: 23
|
||||
main: true
|
||||
invoice_item_11721:
|
||||
id: 11721
|
||||
invoice_id: 5822
|
||||
amount: 3000
|
||||
created_at: '2022-10-04 14:35:40.603969'
|
||||
updated_at: '2022-10-04 14:35:40.608505'
|
||||
description: Panneau de 3 plis mélèze x 1
|
||||
invoice_item_id:
|
||||
footprint: c1ad8c20d080ebc8267ff0d1b668feb8c989c2561be75d311f29f49a03405895
|
||||
object_type: OrderItem
|
||||
object_id: 24
|
||||
main: true
|
||||
|
180
test/fixtures/invoices.yml
vendored
180
test/fixtures/invoices.yml
vendored
@ -124,3 +124,183 @@ invoice_6:
|
||||
invoicing_profile_id: 8
|
||||
operator_profile_id: 1
|
||||
statistic_profile_id: 8
|
||||
invoice_5811:
|
||||
id: 5811
|
||||
total: 4500
|
||||
created_at: '2022-09-20 15:14:22.873707'
|
||||
updated_at: '2022-09-20 15:14:23.496793'
|
||||
reference: '2209002'
|
||||
payment_method: local
|
||||
avoir_date:
|
||||
invoice_id:
|
||||
type:
|
||||
subscription_to_expire:
|
||||
description:
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
coupon_id:
|
||||
footprint: '094590df6330de6a2b5d2ce7230673c7178f2639ca8ceb51ba272795349fff95'
|
||||
environment: development
|
||||
invoicing_profile_id: 3
|
||||
operator_profile_id: 1
|
||||
statistic_profile_id: 3
|
||||
invoice_5812:
|
||||
id: 5812
|
||||
total: 6000
|
||||
created_at: '2022-09-20 15:14:48.345927'
|
||||
updated_at: '2022-09-20 15:14:48.409110'
|
||||
reference: '2209004'
|
||||
payment_method: local
|
||||
avoir_date:
|
||||
invoice_id:
|
||||
type:
|
||||
subscription_to_expire:
|
||||
description:
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
coupon_id:
|
||||
footprint: ea5cc57a8af956f9a3e66ec1f9bd7fe5fe51e1220955cacb11a3cc99d2e6aa54
|
||||
environment: development
|
||||
invoicing_profile_id: 7
|
||||
operator_profile_id: 1
|
||||
statistic_profile_id: 7
|
||||
invoice_5816:
|
||||
id: 5816
|
||||
total: 319
|
||||
created_at: '2022-10-04 12:36:03.060832'
|
||||
updated_at: '2022-10-04 12:36:03.445507'
|
||||
reference: 2210002/VL
|
||||
payment_method: card
|
||||
avoir_date:
|
||||
invoice_id:
|
||||
type:
|
||||
subscription_to_expire:
|
||||
description:
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
coupon_id:
|
||||
footprint: ca8879f07cf1bd29500a9df29ce110843fb204ab0da8140bb4c6e8e908a65e0b
|
||||
environment: development
|
||||
invoicing_profile_id: 4
|
||||
operator_profile_id: 4
|
||||
statistic_profile_id: 4
|
||||
invoice_5817:
|
||||
id: 5817
|
||||
total: 1296
|
||||
created_at: '2022-10-04 13:54:42.975196'
|
||||
updated_at: '2022-10-04 13:54:43.070098'
|
||||
reference: 2210004/VL
|
||||
payment_method: card
|
||||
avoir_date:
|
||||
invoice_id:
|
||||
type:
|
||||
subscription_to_expire:
|
||||
description:
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
coupon_id: 30
|
||||
footprint: 838ae505dfba54f6a69cd341abf8f97fd9370c2acb81e37c6e70d98049d80646
|
||||
environment: development
|
||||
invoicing_profile_id: 4
|
||||
operator_profile_id: 4
|
||||
statistic_profile_id: 4
|
||||
invoice_5818:
|
||||
id: 5818
|
||||
total: 1000
|
||||
created_at: '2022-10-04 14:04:12.742685'
|
||||
updated_at: '2022-10-04 14:04:12.774844'
|
||||
reference: 2210006/VL
|
||||
payment_method: card
|
||||
avoir_date:
|
||||
invoice_id:
|
||||
type:
|
||||
subscription_to_expire:
|
||||
description:
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
coupon_id:
|
||||
footprint: 93db8c6ded7066a71927b6950cf5a9ea69aff25036df3a5a4259615347f2c8b2
|
||||
environment: development
|
||||
invoicing_profile_id: 4
|
||||
operator_profile_id: 4
|
||||
statistic_profile_id: 4
|
||||
invoice_5819:
|
||||
id: 5819
|
||||
total: 4002
|
||||
created_at: '2022-10-04 14:17:52.854636'
|
||||
updated_at: '2022-10-04 14:17:52.898044'
|
||||
reference: 2210008/VL
|
||||
payment_method: card
|
||||
avoir_date:
|
||||
invoice_id:
|
||||
type:
|
||||
subscription_to_expire:
|
||||
description:
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
coupon_id:
|
||||
footprint: bfd2f78a99aadd137f3f28fe8258a46ff8afa69b458f0a6f2dce1205fab22784
|
||||
environment: development
|
||||
invoicing_profile_id: 4
|
||||
operator_profile_id: 4
|
||||
statistic_profile_id: 4
|
||||
invoice_5820:
|
||||
id: 5820
|
||||
total: 12000
|
||||
created_at: '2022-10-04 14:25:37.291945'
|
||||
updated_at: '2022-10-04 14:25:37.341401'
|
||||
reference: '2210010'
|
||||
payment_method: local
|
||||
avoir_date:
|
||||
invoice_id:
|
||||
type:
|
||||
subscription_to_expire:
|
||||
description:
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
coupon_id:
|
||||
footprint: db6a663a25e19229ee93868765e1463ec7bd7856b173c5dd326d70d98369cfc0
|
||||
environment: development
|
||||
invoicing_profile_id: 3
|
||||
operator_profile_id: 1
|
||||
statistic_profile_id: 3
|
||||
invoice_5821:
|
||||
id: 5821
|
||||
total: 12000
|
||||
created_at: '2022-10-04 14:32:28.204985'
|
||||
updated_at: '2022-10-04 14:32:28.292591'
|
||||
reference: '2210012'
|
||||
payment_method: local
|
||||
avoir_date:
|
||||
invoice_id:
|
||||
type:
|
||||
subscription_to_expire:
|
||||
description:
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
coupon_id:
|
||||
footprint: 3ed9a13e5c7155bc3b186f3215b90345cc5520822728796e7c1c00ad5128ed01
|
||||
environment: development
|
||||
invoicing_profile_id: 2
|
||||
operator_profile_id: 1
|
||||
statistic_profile_id: 2
|
||||
invoice_5822:
|
||||
id: 5822
|
||||
total: 3000
|
||||
created_at: '2022-10-04 14:35:40.584472'
|
||||
updated_at: '2022-10-04 14:35:40.637091'
|
||||
reference: '2210014'
|
||||
payment_method: local
|
||||
avoir_date:
|
||||
invoice_id:
|
||||
type:
|
||||
subscription_to_expire:
|
||||
description:
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
coupon_id:
|
||||
footprint: 63d069e72b4992244861e9450b0c3ba3b9b30638af972a631b81578091d2925d
|
||||
environment: development
|
||||
invoicing_profile_id: 2
|
||||
operator_profile_id: 1
|
||||
statistic_profile_id: 2
|
||||
|
129
test/fixtures/order_activities.yml
vendored
Normal file
129
test/fixtures/order_activities.yml
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
order_activity_1:
|
||||
id: 1
|
||||
order_id: 1
|
||||
operator_profile_id:
|
||||
activity_type: paid
|
||||
note:
|
||||
created_at: '2022-09-20 15:14:22.596166'
|
||||
updated_at: '2022-09-20 15:14:22.596166'
|
||||
order_activity_2:
|
||||
id: 2
|
||||
order_id: 2
|
||||
operator_profile_id:
|
||||
activity_type: paid
|
||||
note:
|
||||
created_at: '2022-09-20 15:14:48.328689'
|
||||
updated_at: '2022-09-20 15:14:48.328689'
|
||||
order_activity_6:
|
||||
id: 6
|
||||
order_id: 9
|
||||
operator_profile_id:
|
||||
activity_type: paid
|
||||
note:
|
||||
created_at: '2022-10-04 12:36:02.719677'
|
||||
updated_at: '2022-10-04 12:36:02.719677'
|
||||
order_activity_7:
|
||||
id: 7
|
||||
order_id: 2
|
||||
operator_profile_id: 2437
|
||||
activity_type: ready
|
||||
note: Merci de venir retirer la commande
|
||||
created_at: '2022-10-04 13:37:49.932146'
|
||||
updated_at: '2022-10-04 13:37:49.932146'
|
||||
order_activity_11:
|
||||
id: 11
|
||||
order_id: 9
|
||||
operator_profile_id: 2437
|
||||
activity_type: ready
|
||||
note: ''
|
||||
created_at: '2022-10-04 13:50:30.609274'
|
||||
updated_at: '2022-10-04 13:50:30.609274'
|
||||
order_activity_12:
|
||||
id: 12
|
||||
order_id: 10
|
||||
operator_profile_id:
|
||||
activity_type: paid
|
||||
note:
|
||||
created_at: '2022-10-04 13:54:42.749983'
|
||||
updated_at: '2022-10-04 13:54:42.749983'
|
||||
order_activity_13:
|
||||
id: 13
|
||||
order_id: 10
|
||||
operator_profile_id: 2437
|
||||
activity_type: ready
|
||||
note: ''
|
||||
created_at: '2022-10-04 13:54:56.790702'
|
||||
updated_at: '2022-10-04 13:54:56.790702'
|
||||
order_activity_14:
|
||||
id: 14
|
||||
order_id: 11
|
||||
operator_profile_id:
|
||||
activity_type: paid
|
||||
note:
|
||||
created_at: '2022-10-04 14:04:12.721800'
|
||||
updated_at: '2022-10-04 14:04:12.721800'
|
||||
order_activity_15:
|
||||
id: 15
|
||||
order_id: 11
|
||||
operator_profile_id: 2437
|
||||
activity_type: ready
|
||||
note: ''
|
||||
created_at: '2022-10-04 14:04:28.489152'
|
||||
updated_at: '2022-10-04 14:04:28.489152'
|
||||
order_activity_16:
|
||||
id: 16
|
||||
order_id: 12
|
||||
operator_profile_id:
|
||||
activity_type: paid
|
||||
note:
|
||||
created_at: '2022-10-04 14:17:52.835587'
|
||||
updated_at: '2022-10-04 14:17:52.835587'
|
||||
order_activity_17:
|
||||
id: 17
|
||||
order_id: 12
|
||||
operator_profile_id: 2437
|
||||
activity_type: ready
|
||||
note: "<p>je ne sais pas que te dire <u>mon ami</u></p>"
|
||||
created_at: '2022-10-04 14:22:54.560670'
|
||||
updated_at: '2022-10-04 14:22:54.560670'
|
||||
order_activity_18:
|
||||
id: 18
|
||||
order_id: 5
|
||||
operator_profile_id:
|
||||
activity_type: paid
|
||||
note:
|
||||
created_at: '2022-10-04 14:25:37.278540'
|
||||
updated_at: '2022-10-04 14:25:37.278540'
|
||||
order_activity_19:
|
||||
id: 19
|
||||
order_id: 14
|
||||
operator_profile_id:
|
||||
activity_type: paid
|
||||
note:
|
||||
created_at: '2022-10-04 14:32:27.965847'
|
||||
updated_at: '2022-10-04 14:32:27.965847'
|
||||
order_activity_20:
|
||||
id: 20
|
||||
order_id: 14
|
||||
operator_profile_id: 2437
|
||||
activity_type: ready
|
||||
note: "<p><strong>Lorem ipsum</strong> dolor sit amet</p>"
|
||||
created_at: '2022-10-04 14:33:17.067080'
|
||||
updated_at: '2022-10-04 14:33:17.067080'
|
||||
order_activity_21:
|
||||
id: 21
|
||||
order_id: 15
|
||||
operator_profile_id:
|
||||
activity_type: paid
|
||||
note:
|
||||
created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
updated_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
order_activity_22:
|
||||
id: 22
|
||||
order_id: 15
|
||||
operator_profile_id: 2437
|
||||
activity_type: ready
|
||||
note: "<p>Votre <em>commande</em> est prête, merci de venir la récupérer <strong>jeudi</strong>
|
||||
<u>après 14 h</u>.</p>"
|
||||
created_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
130
test/fixtures/order_items.yml
vendored
Normal file
130
test/fixtures/order_items.yml
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
order_item_1:
|
||||
id: 1
|
||||
order_id: 1
|
||||
orderable_type: Product
|
||||
orderable_id: 18
|
||||
amount: 4000
|
||||
quantity: 1
|
||||
is_offered:
|
||||
created_at: '2022-09-20 15:14:05.605885'
|
||||
updated_at: '2022-09-20 15:14:05.605885'
|
||||
order_item_2:
|
||||
id: 2
|
||||
order_id: 1
|
||||
orderable_type: Product
|
||||
orderable_id: 13
|
||||
amount: 500
|
||||
quantity: 1
|
||||
is_offered:
|
||||
created_at: '2022-09-20 15:14:09.022448'
|
||||
updated_at: '2022-09-20 15:14:09.022448'
|
||||
order_item_3:
|
||||
id: 3
|
||||
order_id: 2
|
||||
orderable_type: Product
|
||||
orderable_id: 15
|
||||
amount: 1500
|
||||
quantity: 4
|
||||
is_offered:
|
||||
created_at: '2022-09-20 15:14:34.899658'
|
||||
updated_at: '2022-09-20 15:14:34.899658'
|
||||
order_item_11:
|
||||
id: 11
|
||||
order_id: 5
|
||||
orderable_type: Product
|
||||
orderable_id: 18
|
||||
amount: 4000
|
||||
quantity: 3
|
||||
is_offered:
|
||||
created_at: '2022-09-28 08:31:30.377083'
|
||||
updated_at: '2022-10-04 08:34:25.130457'
|
||||
order_item_16:
|
||||
id: 16
|
||||
order_id: 9
|
||||
orderable_type: Product
|
||||
orderable_id: 23
|
||||
amount: 119
|
||||
quantity: 1
|
||||
is_offered:
|
||||
created_at: '2022-10-04 12:35:39.730968'
|
||||
updated_at: '2022-10-04 12:35:39.730968'
|
||||
order_item_17:
|
||||
id: 17
|
||||
order_id: 9
|
||||
orderable_type: Product
|
||||
orderable_id: 22
|
||||
amount: 200
|
||||
quantity: 1
|
||||
is_offered:
|
||||
created_at: '2022-10-04 12:35:40.562076'
|
||||
updated_at: '2022-10-04 12:35:40.562076'
|
||||
order_item_18:
|
||||
id: 18
|
||||
order_id: 10
|
||||
orderable_type: Product
|
||||
orderable_id: 23
|
||||
amount: 119
|
||||
quantity: 1
|
||||
is_offered:
|
||||
created_at: '2022-10-04 13:54:19.042858'
|
||||
updated_at: '2022-10-04 13:54:19.042858'
|
||||
order_item_19:
|
||||
id: 19
|
||||
order_id: 10
|
||||
orderable_type: Product
|
||||
orderable_id: 15
|
||||
amount: 1500
|
||||
quantity: 1
|
||||
is_offered:
|
||||
created_at: '2022-10-04 13:54:22.649153'
|
||||
updated_at: '2022-10-04 13:54:22.649153'
|
||||
order_item_20:
|
||||
id: 20
|
||||
order_id: 11
|
||||
orderable_type: Product
|
||||
orderable_id: 11
|
||||
amount: 1000
|
||||
quantity: 1
|
||||
is_offered:
|
||||
created_at: '2022-10-04 14:03:59.721736'
|
||||
updated_at: '2022-10-04 14:03:59.721736'
|
||||
order_item_21:
|
||||
id: 21
|
||||
order_id: 12
|
||||
orderable_type: Product
|
||||
orderable_id: 20
|
||||
amount: 1
|
||||
quantity: 2
|
||||
is_offered:
|
||||
created_at: '2022-10-04 14:05:23.583721'
|
||||
updated_at: '2022-10-04 14:17:41.866526'
|
||||
order_item_22:
|
||||
id: 22
|
||||
order_id: 12
|
||||
orderable_type: Product
|
||||
orderable_id: 18
|
||||
amount: 4000
|
||||
quantity: 1
|
||||
is_offered:
|
||||
created_at: '2022-10-04 14:17:33.257776'
|
||||
updated_at: '2022-10-04 14:17:33.257776'
|
||||
order_item_23:
|
||||
id: 23
|
||||
order_id: 14
|
||||
orderable_type: Product
|
||||
orderable_id: 18
|
||||
amount: 4000
|
||||
quantity: 3
|
||||
is_offered:
|
||||
created_at: '2022-10-04 14:31:51.106853'
|
||||
updated_at: '2022-10-04 14:31:54.194063'
|
||||
order_item_24:
|
||||
id: 24
|
||||
order_id: 15
|
||||
orderable_type: Product
|
||||
orderable_id: 17
|
||||
amount: 3000
|
||||
quantity: 1
|
||||
is_offered:
|
||||
created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
updated_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
162
test/fixtures/orders.yml
vendored
Normal file
162
test/fixtures/orders.yml
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
order_1:
|
||||
id: 1
|
||||
statistic_profile_id: 3
|
||||
operator_profile_id: 1
|
||||
token: 3R9wtsPjyYMHKqy-I2V5Cg1661868752184
|
||||
reference:
|
||||
state: paid
|
||||
total: 4500
|
||||
created_at: '2022-08-30 14:12:32.213832'
|
||||
updated_at: '2022-09-20 15:14:23.501369'
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
payment_method: local
|
||||
footprint:
|
||||
environment: test
|
||||
coupon_id:
|
||||
paid_total: 4500
|
||||
invoice_id: 5811
|
||||
order_2:
|
||||
id: 2
|
||||
statistic_profile_id: 7
|
||||
operator_profile_id: 1
|
||||
token: TDKq6p4f3WgDRMIvplEqpg1663686863871
|
||||
reference: '005877-09-22'
|
||||
state: ready
|
||||
total: 6000
|
||||
created_at: '2022-09-20 15:14:23.887098'
|
||||
updated_at: '2022-10-04 13:37:49.935380'
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
payment_method: local
|
||||
footprint:
|
||||
environment: test
|
||||
coupon_id:
|
||||
paid_total: 6000
|
||||
invoice_id: 5812
|
||||
order_5:
|
||||
id: 5
|
||||
statistic_profile_id: 3
|
||||
operator_profile_id: 1
|
||||
token: UbTOaTePhajDJPPH42e3yw1664353619348
|
||||
reference: '005882-09-22'
|
||||
state: paid
|
||||
total: 12000
|
||||
created_at: '2022-09-28 08:26:59.368029'
|
||||
updated_at: '2022-10-04 14:25:37.345897'
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
payment_method: local
|
||||
footprint:
|
||||
environment: test
|
||||
coupon_id:
|
||||
paid_total: 12000
|
||||
invoice_id: 5820
|
||||
order_9:
|
||||
id: 9
|
||||
statistic_profile_id: 4
|
||||
operator_profile_id: 4
|
||||
token: 8jOZwd2vkE86x26cg167iQ1664886886040
|
||||
reference: '005888-10-22'
|
||||
state: ready
|
||||
total: 319
|
||||
created_at: '2022-10-04 12:34:46.054976'
|
||||
updated_at: '2022-10-04 13:50:30.611456'
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
payment_method: card
|
||||
footprint:
|
||||
environment: test
|
||||
coupon_id:
|
||||
paid_total: 319
|
||||
invoice_id: 5816
|
||||
order_10:
|
||||
id: 10
|
||||
statistic_profile_id: 4
|
||||
operator_profile_id: 4
|
||||
token: ryrsm4yj21DTJv1qIgMuGA1664886964105
|
||||
reference: '005890-10-22'
|
||||
state: ready
|
||||
total: 1619
|
||||
created_at: '2022-10-04 12:36:04.117389'
|
||||
updated_at: '2022-10-04 13:54:56.792550'
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
payment_method: card
|
||||
footprint:
|
||||
environment: test
|
||||
coupon_id: 30
|
||||
paid_total: 1296
|
||||
invoice_id: 5817
|
||||
order_11:
|
||||
id: 11
|
||||
statistic_profile_id: 4
|
||||
operator_profile_id: 4
|
||||
token: ogvv31XzLE0zFLc_c8k4Sw1664891683573
|
||||
reference: '005892-10-22'
|
||||
state: ready
|
||||
total: 1000
|
||||
created_at: '2022-10-04 13:54:43.617309'
|
||||
updated_at: '2022-10-04 14:04:28.490690'
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
payment_method: card
|
||||
footprint:
|
||||
environment: test
|
||||
coupon_id:
|
||||
paid_total: 1000
|
||||
invoice_id: 5818
|
||||
order_12:
|
||||
id: 12
|
||||
statistic_profile_id: 4
|
||||
operator_profile_id: 4
|
||||
token: ttG9U892Bu0gbu8OnJkwTw1664892253183
|
||||
reference: '005894-10-22'
|
||||
state: ready
|
||||
total: 4002
|
||||
created_at: '2022-10-04 14:04:13.206078'
|
||||
updated_at: '2022-10-04 14:22:54.562186'
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
payment_method: card
|
||||
footprint:
|
||||
environment: test
|
||||
coupon_id:
|
||||
paid_total: 4002
|
||||
invoice_id: 5819
|
||||
order_14:
|
||||
id: 14
|
||||
statistic_profile_id: 2
|
||||
operator_profile_id: 1
|
||||
token: QsDdf_8YHL6mxUSMno-deg1664893537749
|
||||
reference: '005898-10-22'
|
||||
state: ready
|
||||
total: 12000
|
||||
created_at: '2022-10-04 14:25:37.773536'
|
||||
updated_at: '2022-10-04 14:33:17.068764'
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
payment_method: local
|
||||
footprint:
|
||||
environment: test
|
||||
coupon_id:
|
||||
paid_total: 12000
|
||||
invoice_id: 5821
|
||||
order_15:
|
||||
id: 15
|
||||
statistic_profile_id: 2
|
||||
operator_profile_id: 1
|
||||
token: JOLm4fAZjFSkmWzAX3KObw1664893948693
|
||||
reference: '005900-10-22'
|
||||
state: ready
|
||||
total: 3000
|
||||
created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
wallet_amount:
|
||||
wallet_transaction_id:
|
||||
payment_method: local
|
||||
footprint:
|
||||
environment: test
|
||||
coupon_id:
|
||||
paid_total: 3000
|
||||
invoice_id: 5822
|
49
test/fixtures/product_categories.yml
vendored
Normal file
49
test/fixtures/product_categories.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
product_category_1:
|
||||
id: 1
|
||||
name: Consommables
|
||||
slug: consommables
|
||||
parent_id:
|
||||
position: 0
|
||||
created_at: '2022-08-23 07:55:35.573968'
|
||||
updated_at: '2022-08-23 07:55:35.573968'
|
||||
product_category_2:
|
||||
id: 2
|
||||
name: Fournitures
|
||||
slug: fournitures
|
||||
parent_id:
|
||||
position: 1
|
||||
created_at: '2022-08-23 07:55:49.380035'
|
||||
updated_at: '2022-10-05 11:42:52.965226'
|
||||
product_category_3:
|
||||
id: 3
|
||||
name: Filament imprimante 3D
|
||||
slug: filament-imprimante-3d
|
||||
parent_id: 1
|
||||
position: 0
|
||||
created_at: '2022-08-23 07:56:05.254962'
|
||||
updated_at: '2022-08-23 07:56:05.254962'
|
||||
product_category_4:
|
||||
id: 4
|
||||
name: Objets créés au fablab
|
||||
slug: objets-crees-au-fablab
|
||||
parent_id:
|
||||
position: 2
|
||||
created_at: '2022-09-14 13:39:03.170717'
|
||||
updated_at: '2022-10-05 11:42:52.965226'
|
||||
product_category_5:
|
||||
id: 5
|
||||
name: Bois
|
||||
slug: bois
|
||||
parent_id: 1
|
||||
position: 1
|
||||
created_at: '2022-09-14 14:57:58.136610'
|
||||
updated_at: '2022-09-14 14:57:58.136610'
|
||||
product_category_6:
|
||||
id: 6
|
||||
name: Stickers
|
||||
slug: stickers
|
||||
parent_id: 4
|
||||
position: 0
|
||||
created_at: '2022-09-28 08:12:35.823487'
|
||||
updated_at: '2022-09-28 08:12:35.823487'
|
||||
|
275
test/fixtures/product_stock_movements.yml
vendored
Normal file
275
test/fixtures/product_stock_movements.yml
vendored
Normal file
@ -0,0 +1,275 @@
|
||||
product_stock_movement_26:
|
||||
id: 26
|
||||
product_id: 3
|
||||
quantity: 1
|
||||
reason: inward_stock
|
||||
stock_type: internal
|
||||
remaining_stock: 1
|
||||
date: '2022-09-13 12:52:52.656974'
|
||||
created_at: '2022-09-13 12:52:52.669247'
|
||||
updated_at: '2022-09-13 12:52:52.669247'
|
||||
order_item_id:
|
||||
product_stock_movement_33:
|
||||
id: 33
|
||||
product_id: 11
|
||||
quantity: 10
|
||||
reason: inward_stock
|
||||
stock_type: external
|
||||
remaining_stock: 10
|
||||
date: '2022-09-14 13:41:16.204940'
|
||||
created_at: '2022-09-14 13:41:16.212290'
|
||||
updated_at: '2022-09-14 13:41:16.212290'
|
||||
order_item_id:
|
||||
product_stock_movement_34:
|
||||
id: 34
|
||||
product_id: 12
|
||||
quantity: 1
|
||||
reason: returned
|
||||
stock_type: internal
|
||||
remaining_stock: 1
|
||||
date: '2022-09-14 13:42:53.702489'
|
||||
created_at: '2022-09-14 13:42:53.706634'
|
||||
updated_at: '2022-09-14 13:42:53.706634'
|
||||
order_item_id:
|
||||
product_stock_movement_35:
|
||||
id: 35
|
||||
product_id: 13
|
||||
quantity: 1000
|
||||
reason: inward_stock
|
||||
stock_type: external
|
||||
remaining_stock: 1000
|
||||
date: '2022-09-14 13:47:18.120615'
|
||||
created_at: '2022-09-14 13:47:18.131919'
|
||||
updated_at: '2022-09-14 13:47:18.131919'
|
||||
order_item_id:
|
||||
product_stock_movement_36:
|
||||
id: 36
|
||||
product_id: 14
|
||||
quantity: 800
|
||||
reason: inward_stock
|
||||
stock_type: external
|
||||
remaining_stock: 800
|
||||
date: '2022-09-14 13:48:05.025884'
|
||||
created_at: '2022-09-14 13:48:05.035926'
|
||||
updated_at: '2022-09-14 13:48:05.035926'
|
||||
order_item_id:
|
||||
product_stock_movement_37:
|
||||
id: 37
|
||||
product_id: 15
|
||||
quantity: 600
|
||||
reason: inward_stock
|
||||
stock_type: external
|
||||
remaining_stock: 600
|
||||
date: '2022-09-14 13:49:08.203980'
|
||||
created_at: '2022-09-14 13:49:08.240896'
|
||||
updated_at: '2022-09-14 13:49:08.240896'
|
||||
order_item_id:
|
||||
product_stock_movement_38:
|
||||
id: 38
|
||||
product_id: 16
|
||||
quantity: 100
|
||||
reason: inward_stock
|
||||
stock_type: external
|
||||
remaining_stock: 100
|
||||
date: '2022-09-14 13:50:12.581463'
|
||||
created_at: '2022-09-14 13:50:12.591335'
|
||||
updated_at: '2022-09-14 13:50:12.591335'
|
||||
order_item_id:
|
||||
product_stock_movement_39:
|
||||
id: 39
|
||||
product_id: 17
|
||||
quantity: 100
|
||||
reason: inward_stock
|
||||
stock_type: external
|
||||
remaining_stock: 100
|
||||
date: '2022-09-14 13:51:12.627746'
|
||||
created_at: '2022-09-14 13:51:12.636692'
|
||||
updated_at: '2022-09-14 13:51:12.636692'
|
||||
order_item_id:
|
||||
product_stock_movement_40:
|
||||
id: 40
|
||||
product_id: 18
|
||||
quantity: 20
|
||||
reason: inward_stock
|
||||
stock_type: external
|
||||
remaining_stock: 20
|
||||
date: '2022-09-14 13:52:08.655537'
|
||||
created_at: '2022-09-14 13:52:08.672419'
|
||||
updated_at: '2022-09-14 13:52:08.672419'
|
||||
order_item_id:
|
||||
product_stock_movement_41:
|
||||
id: 41
|
||||
product_id: 18
|
||||
quantity: -1
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 19
|
||||
date: '2022-09-20 15:14:22.629666'
|
||||
created_at: '2022-09-20 15:14:22.651877'
|
||||
updated_at: '2022-09-20 15:14:22.651877'
|
||||
order_item_id: 1
|
||||
product_stock_movement_42:
|
||||
id: 42
|
||||
product_id: 13
|
||||
quantity: -1
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 999
|
||||
date: '2022-09-20 15:14:22.688402'
|
||||
created_at: '2022-09-20 15:14:22.692461'
|
||||
updated_at: '2022-09-20 15:14:22.692461'
|
||||
order_item_id: 2
|
||||
product_stock_movement_43:
|
||||
id: 43
|
||||
product_id: 15
|
||||
quantity: -4
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 596
|
||||
date: '2022-09-20 15:14:48.330513'
|
||||
created_at: '2022-09-20 15:14:48.334360'
|
||||
updated_at: '2022-09-20 15:14:48.334360'
|
||||
order_item_id: 3
|
||||
product_stock_movement_56:
|
||||
id: 56
|
||||
product_id: 22
|
||||
quantity: 1000
|
||||
reason: inward_stock
|
||||
stock_type: external
|
||||
remaining_stock: 1000
|
||||
date: '2022-10-03 14:00:49.950506'
|
||||
created_at: '2022-10-03 14:00:50.107429'
|
||||
updated_at: '2022-10-03 14:00:50.107429'
|
||||
order_item_id:
|
||||
product_stock_movement_57:
|
||||
id: 57
|
||||
product_id: 22
|
||||
quantity: 1000
|
||||
reason: inward_stock
|
||||
stock_type: internal
|
||||
remaining_stock: 1000
|
||||
date: '2022-10-03 14:00:49.950569'
|
||||
created_at: '2022-10-03 14:00:50.136314'
|
||||
updated_at: '2022-10-03 14:00:50.136314'
|
||||
order_item_id:
|
||||
product_stock_movement_58:
|
||||
id: 58
|
||||
product_id: 23
|
||||
quantity: 1000
|
||||
reason: inward_stock
|
||||
stock_type: internal
|
||||
remaining_stock: 1000
|
||||
date: '2022-10-03 14:02:00.518281'
|
||||
created_at: '2022-10-03 14:02:00.524640'
|
||||
updated_at: '2022-10-03 14:02:00.524640'
|
||||
order_item_id:
|
||||
product_stock_movement_59:
|
||||
id: 59
|
||||
product_id: 23
|
||||
quantity: 1000
|
||||
reason: inward_stock
|
||||
stock_type: external
|
||||
remaining_stock: 1000
|
||||
date: '2022-10-03 14:02:00.518337'
|
||||
created_at: '2022-10-03 14:02:00.526611'
|
||||
updated_at: '2022-10-03 14:02:00.526611'
|
||||
order_item_id:
|
||||
product_stock_movement_61:
|
||||
id: 61
|
||||
product_id: 23
|
||||
quantity: -1
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 999
|
||||
date: '2022-10-04 12:36:02.765304'
|
||||
created_at: '2022-10-04 12:36:02.788575'
|
||||
updated_at: '2022-10-04 12:36:02.788575'
|
||||
order_item_id: 16
|
||||
product_stock_movement_62:
|
||||
id: 62
|
||||
product_id: 22
|
||||
quantity: -1
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 999
|
||||
date: '2022-10-04 12:36:02.827107'
|
||||
created_at: '2022-10-04 12:36:02.832197'
|
||||
updated_at: '2022-10-04 12:36:02.832197'
|
||||
order_item_id: 17
|
||||
product_stock_movement_63:
|
||||
id: 63
|
||||
product_id: 23
|
||||
quantity: -1
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 998
|
||||
date: '2022-10-04 13:54:42.768616'
|
||||
created_at: '2022-10-04 13:54:42.783563'
|
||||
updated_at: '2022-10-04 13:54:42.783563'
|
||||
order_item_id: 18
|
||||
product_stock_movement_64:
|
||||
id: 64
|
||||
product_id: 15
|
||||
quantity: -1
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 595
|
||||
date: '2022-10-04 13:54:42.785294'
|
||||
created_at: '2022-10-04 13:54:42.788610'
|
||||
updated_at: '2022-10-04 13:54:42.788610'
|
||||
order_item_id: 19
|
||||
product_stock_movement_65:
|
||||
id: 65
|
||||
product_id: 11
|
||||
quantity: -1
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 9
|
||||
date: '2022-10-04 14:04:12.723429'
|
||||
created_at: '2022-10-04 14:04:12.729897'
|
||||
updated_at: '2022-10-04 14:04:12.729897'
|
||||
order_item_id: 20
|
||||
product_stock_movement_67:
|
||||
id: 67
|
||||
product_id: 18
|
||||
quantity: -1
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 18
|
||||
date: '2022-10-04 14:17:52.842942'
|
||||
created_at: '2022-10-04 14:17:52.846168'
|
||||
updated_at: '2022-10-04 14:17:52.846168'
|
||||
order_item_id: 22
|
||||
product_stock_movement_68:
|
||||
id: 68
|
||||
product_id: 18
|
||||
quantity: -3
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 15
|
||||
date: '2022-10-04 14:25:37.280032'
|
||||
created_at: '2022-10-04 14:25:37.283491'
|
||||
updated_at: '2022-10-04 14:25:37.283491'
|
||||
order_item_id: 11
|
||||
product_stock_movement_69:
|
||||
id: 69
|
||||
product_id: 18
|
||||
quantity: -3
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 12
|
||||
date: '2022-10-04 14:32:28.002830'
|
||||
created_at: '2022-10-04 14:32:28.023296'
|
||||
updated_at: '2022-10-04 14:32:28.023296'
|
||||
order_item_id: 23
|
||||
product_stock_movement_70:
|
||||
id: 70
|
||||
product_id: 17
|
||||
quantity: -1
|
||||
reason: sold
|
||||
stock_type: external
|
||||
remaining_stock: 99
|
||||
date: '2022-10-04 14:35:40.556113'
|
||||
created_at: '2022-10-04 14:35:40.560251'
|
||||
updated_at: '2022-10-04 14:35:40.560251'
|
||||
order_item_id: 24
|
182
test/fixtures/products.yml
vendored
Normal file
182
test/fixtures/products.yml
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
product_3:
|
||||
id: 3
|
||||
name: Caisse en bois
|
||||
slug: caisse-en-bois
|
||||
sku: '1694813216840'
|
||||
description: "<p>C'est un superbe caisse en bois massif</p>"
|
||||
is_active: true
|
||||
product_category_id: 4
|
||||
amount: 52300
|
||||
quantity_min: 10
|
||||
stock: '{"external": 0, "internal": 1}'
|
||||
low_stock_alert: true
|
||||
low_stock_threshold: 10
|
||||
created_at: '2022-09-13 10:05:07.010322'
|
||||
updated_at: '2022-09-14 13:39:55.309956'
|
||||
product_11:
|
||||
id: 11
|
||||
name: Bulldozer
|
||||
slug: bulldozer
|
||||
sku: '816516515'
|
||||
description: "<p>Jouet pour enfants</p>"
|
||||
is_active: true
|
||||
product_category_id: 4
|
||||
amount: 1000
|
||||
quantity_min: 1
|
||||
stock: '{"external": 9, "internal": 0}'
|
||||
low_stock_alert: false
|
||||
low_stock_threshold:
|
||||
created_at: '2022-09-14 13:41:16.207154'
|
||||
updated_at: '2022-10-04 14:04:12.727452'
|
||||
product_12:
|
||||
id: 12
|
||||
name: Casque à pointe
|
||||
slug: casque-a-pointe
|
||||
sku: '10210706'
|
||||
description: "<p>Authentique casque à pointe allemand de la 1ère guerre mondiale</p>"
|
||||
is_active: true
|
||||
product_category_id: 4
|
||||
amount: 142300
|
||||
quantity_min: 1
|
||||
stock: '{"external": 0, "internal": 1}'
|
||||
low_stock_alert: false
|
||||
low_stock_threshold:
|
||||
created_at: '2022-09-14 13:42:36.729625'
|
||||
updated_at: '2022-09-14 13:42:53.704455'
|
||||
product_13:
|
||||
id: 13
|
||||
name: Panneaux de MDF
|
||||
slug: panneaux-de-mdf
|
||||
sku: 3-8612
|
||||
description: ''
|
||||
is_active: true
|
||||
product_category_id: 5
|
||||
amount: 500
|
||||
quantity_min: 1
|
||||
stock: '{"external": 999, "internal": 0}'
|
||||
low_stock_alert: false
|
||||
low_stock_threshold:
|
||||
created_at: '2022-09-14 13:47:18.123531'
|
||||
updated_at: '2022-09-20 15:14:22.690742'
|
||||
product_14:
|
||||
id: 14
|
||||
name: Panneau de mélaminé
|
||||
slug: panneau-de-melamine
|
||||
sku: 12-4512
|
||||
description: ''
|
||||
is_active: true
|
||||
product_category_id: 5
|
||||
amount: 1000
|
||||
quantity_min: 1
|
||||
stock: '{"external": 800, "internal": 0}'
|
||||
low_stock_alert: false
|
||||
low_stock_threshold:
|
||||
created_at: '2022-09-14 13:48:05.028266'
|
||||
updated_at: '2022-09-14 14:58:28.577253'
|
||||
product_15:
|
||||
id: 15
|
||||
name: Panneau de contre-plaqué
|
||||
slug: panneau-de-contre-plaque
|
||||
sku: 12-4613
|
||||
description: ''
|
||||
is_active: true
|
||||
product_category_id: 5
|
||||
amount: 1500
|
||||
quantity_min: 1
|
||||
stock: '{"external": 595, "internal": 0}'
|
||||
low_stock_alert: false
|
||||
low_stock_threshold:
|
||||
created_at: '2022-09-14 13:49:08.233064'
|
||||
updated_at: '2022-10-04 13:54:42.787290'
|
||||
product_16:
|
||||
id: 16
|
||||
name: Panneau d'OSB
|
||||
slug: panneau-osb
|
||||
sku: 14-14488
|
||||
description: ''
|
||||
is_active: true
|
||||
product_category_id: 5
|
||||
amount: 1300
|
||||
quantity_min: 1
|
||||
stock: '{"external": 100, "internal": 0}'
|
||||
low_stock_alert: false
|
||||
low_stock_threshold:
|
||||
created_at: '2022-09-14 13:50:12.584041'
|
||||
updated_at: '2022-09-14 14:58:38.374112'
|
||||
product_17:
|
||||
id: 17
|
||||
name: Panneau de 3 plis mélèze
|
||||
slug: panneau-de-3-plis-meleze
|
||||
sku: 14-47887
|
||||
description: ''
|
||||
is_active: true
|
||||
product_category_id: 5
|
||||
amount: 3000
|
||||
quantity_min: 1
|
||||
stock: '{"external": 99, "internal": 0}'
|
||||
low_stock_alert: false
|
||||
low_stock_threshold:
|
||||
created_at: '2022-09-14 13:51:12.630109'
|
||||
updated_at: '2022-10-04 14:35:40.558485'
|
||||
product_18:
|
||||
id: 18
|
||||
name: Tablette lamellé-collé
|
||||
slug: tablette-lamelle-colle
|
||||
sku: 14-879895
|
||||
description: ''
|
||||
is_active: true
|
||||
product_category_id: 5
|
||||
amount: 4000
|
||||
quantity_min: 1
|
||||
stock: '{"external": 12, "internal": 0}'
|
||||
low_stock_alert: false
|
||||
low_stock_threshold:
|
||||
created_at: '2022-09-14 13:52:08.659248'
|
||||
updated_at: '2022-10-04 14:32:28.021046'
|
||||
product_20:
|
||||
id: 20
|
||||
name: Sticker Hello
|
||||
slug: sticker-hello
|
||||
sku: 63-44801
|
||||
description: <p>un joli sticker en forme de <a target="_blank" rel="noopener noreferrer nofollow"
|
||||
href="https://www.example.com/hello">smiley</a> qui dit bonjour</p>
|
||||
is_active: true
|
||||
product_category_id: 6
|
||||
amount: 1
|
||||
quantity_min: 1
|
||||
stock: '{"external": 15, "internal": 0}'
|
||||
low_stock_alert: false
|
||||
low_stock_threshold:
|
||||
created_at: '2022-09-28 08:16:32.348880'
|
||||
updated_at: '2022-10-04 14:17:52.839249'
|
||||
product_22:
|
||||
id: 22
|
||||
name: Filament PLA bleu
|
||||
slug: filament-pla-bleu
|
||||
sku: 984-777
|
||||
description: <p><a target="_blank" rel="noopener noreferrer nofollow" href="https://www.filimprimante3d.fr/content/80-le-pla-c-est-quoi-comment-choisir-son-filament-pla">Filament
|
||||
PLA</a> 1,75 mm de couleur bleue</p>
|
||||
is_active: true
|
||||
product_category_id: 3
|
||||
amount: 200
|
||||
quantity_min: 1
|
||||
stock: '{"external": 999, "internal": 1000}'
|
||||
low_stock_alert: false
|
||||
low_stock_threshold:
|
||||
created_at: '2022-10-03 14:00:49.967342'
|
||||
updated_at: '2022-10-04 12:36:02.830248'
|
||||
product_23:
|
||||
id: 23
|
||||
name: Filament PLA blanc
|
||||
slug: filament-pla-blanc
|
||||
sku: 178-774
|
||||
description: "<p>Filament PLA 1,75 mm blanc</p>"
|
||||
is_active: true
|
||||
product_category_id: 3
|
||||
amount: 119
|
||||
quantity_min: 1
|
||||
stock: '{"external": 998, "internal": 1000}'
|
||||
low_stock_alert: false
|
||||
low_stock_threshold:
|
||||
created_at: '2022-10-03 14:01:43.706366'
|
||||
updated_at: '2022-10-04 13:54:42.782174'
|
15
test/fixtures/users_roles.yml
vendored
15
test/fixtures/users_roles.yml
vendored
@ -27,3 +27,18 @@ users_role_6:
|
||||
user_id: 6
|
||||
role_id: 4
|
||||
|
||||
users_role_7:
|
||||
user_id: 7
|
||||
role_id: 2
|
||||
|
||||
users_role_8:
|
||||
user_id: 8
|
||||
role_id: 2
|
||||
|
||||
users_role_9:
|
||||
user_id: 9
|
||||
role_id: 2
|
||||
|
||||
users_role_10:
|
||||
user_id: 10
|
||||
role_id: 2
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
require 'test_helper'
|
||||
|
||||
class StatisticServiceTest < ActionDispatch::IntegrationTest
|
||||
class ReservationSubscriptionStatisticServiceTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
@user = User.members.without_subscription.first
|
||||
@admin = User.with_role(:admin).first
|
30
test/services/statistics/store_statistic_service_test.rb
Normal file
30
test/services/statistics/store_statistic_service_test.rb
Normal file
@ -0,0 +1,30 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'test_helper'
|
||||
|
||||
class StoreStatisticServiceTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
@order = Order.find(15)
|
||||
end
|
||||
|
||||
test 'build stats about orders' do
|
||||
# Build the stats for the last 3 days, we expect the above invoices (reservations+subscription) to appear in the resulting stats
|
||||
::Statistics::BuilderService.generate_statistic({ start_date: DateTime.current.beginning_of_day,
|
||||
end_date: DateTime.current.end_of_day })
|
||||
|
||||
Stats::Order.refresh_index!
|
||||
|
||||
# we should find order id 15 (created today)
|
||||
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)
|
||||
end
|
||||
|
||||
def check_statistics_on_user(stat)
|
||||
assert_equal @order.statistic_profile.str_gender, stat['gender']
|
||||
assert_equal @order.statistic_profile.age.to_i, stat['age']
|
||||
assert_equal @order.statistic_profile.group.slug, stat['group']
|
||||
end
|
||||
end
|
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'test_helper'
|
||||
|
||||
class WalletServiceTest < ActiveSupport::TestCase
|
||||
@ -54,9 +56,9 @@ class WalletServiceTest < ActiveSupport::TestCase
|
||||
test 'rollback debited amount if has an error when create wallet transaction' do
|
||||
service = WalletService.new(wallet: @vlonchamp_wallet)
|
||||
expected_amount = @vlonchamp_wallet.amount
|
||||
transaction = service.debit(5)
|
||||
transaction = service.debit('error')
|
||||
@vlonchamp_wallet.reload
|
||||
assert_equal @vlonchamp_wallet.amount, expected_amount
|
||||
assert_equal expected_amount, @vlonchamp_wallet.amount
|
||||
assert_not transaction
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user