Skip to content

Commit

Permalink
Merge branch 'dev' for release 5.9.1
Browse files Browse the repository at this point in the history
  • Loading branch information
sylvainbx committed Mar 22, 2023
2 parents bf40eae + ae904c0 commit 9683498
Show file tree
Hide file tree
Showing 35 changed files with 502 additions and 189 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog Fab-manager

## v5.9.1 2023 March 22

- Fix a bug: logical sequence of invoices references has duplicates
- Fix a bug: in some cases, unable to export to excel files
- Fix a security issue: updated rack to 2.2.6.4 to fix [CVE-2023-27539](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-27539)

## v5.9.0 2023 March 20

- Ability to restrict machine reservations per plan
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ GEM
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.6.1)
rack (2.2.6.3)
rack (2.2.6.4)
rack-oauth2 (1.19.0)
activesupport
attr_required
Expand Down
4 changes: 2 additions & 2 deletions app/frontend/src/javascript/controllers/trainings.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,13 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$tra
// the moment when the slot selection changed for the last time, used to trigger changes in the cart
$scope.selectionTime = null;

// the last clicked event in the calender
// the last clicked event in the calendar
$scope.selectedEvent = null;

// indicates the state of the current view : calendar or plans information
$scope.plansAreShown = false;

// will store the user's plan if he choosed to buy one
// will store the user's plan if he chose to buy one
$scope.selectedPlan = null;

// the moment when the plan selection changed for the last time, used to trigger changes in the cart
Expand Down
11 changes: 10 additions & 1 deletion app/models/availability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ class Availability < ApplicationRecord
validate :length_must_be_slot_multiple, unless: proc { end_at.blank? or start_at.blank? }
validate :should_be_associated

# cache
after_update :refresh_places_cache

## elastic callbacks
after_save { AvailabilityIndexerWorker.perform_async(:index, id) }
after_destroy { AvailabilityIndexerWorker.perform_async(:delete, id) }
Expand Down Expand Up @@ -128,7 +131,7 @@ def reserved_users
slots.map(&:reserved_users).flatten
end

# @param user [User]
# @param user_id [Integer]
# @return [Boolean]
def reserved_by?(user_id)
reserved_users.include?(user_id)
Expand Down Expand Up @@ -195,4 +198,10 @@ def should_be_associated

errors.add(:machine_ids, I18n.t('availabilities.must_be_associated_with_at_least_1_machine'))
end

def refresh_places_cache
slots.each do |slot|
Slots::PlacesCacheService.refresh(slot)
end
end
end
4 changes: 0 additions & 4 deletions app/models/avoir.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ class Avoir < Invoice

delegate :order_number, to: :invoice

def generate_reference
super(created_at)
end

def expire_subscription
user.subscription.expire
end
Expand Down
2 changes: 0 additions & 2 deletions app/models/footprintable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ def debug_footprint
FootprintService.debug_footprint(self.class, self)
end

#protected

def compute_footprint
FootprintService.compute_footprint(self.class, self)
end
Expand Down
6 changes: 2 additions & 4 deletions app/models/invoice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,9 @@ def filename
end

def order_number
return order.reference unless order.nil?
return order.reference unless order.nil? || order.reference.nil?

if !payment_schedule_item.nil? && !payment_schedule_item.first?
return payment_schedule_item.payment_schedule.ordered_items.first.invoice.order_number
end
return payment_schedule_item.payment_schedule.order_number if !payment_schedule_item.nil? && !payment_schedule_item.first?

PaymentDocumentService.generate_order_number(self)
end
Expand Down
2 changes: 2 additions & 0 deletions app/models/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class Order < PaymentDocument

delegate :user, to: :statistic_profile

alias_attribute :order_number, :reference

def generate_reference(_date = Time.current)
self.reference = PaymentDocumentService.generate_order_number(self)
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/payment_document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class PaymentDocument < Footprintable
self.abstract_class = true

def generate_reference(date = Time.current)
def generate_reference(date = created_at)
self.reference = PaymentDocumentService.generate_reference(self, date: date)
end

Expand Down
4 changes: 4 additions & 0 deletions app/models/payment_schedule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def filename
"#{prefix}-#{id}_#{created_at.strftime('%d%m%Y')}.pdf"
end

def order_number
ordered_items.first&.invoice&.order_number || PaymentDocumentService.generate_order_number(self)
end

##
# This is useful to check the first item because its amount may be different from the others
##
Expand Down
10 changes: 7 additions & 3 deletions app/models/statistic_type.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# frozen_string_literal: true

# Allows splinting a StatisticIndex into multiple types.
# e.g. The StatisticIndex "subscriptions" may have types like "1 month", "1 year", etc.
class StatisticType < ApplicationRecord
has_one :statistic_index
has_many :statistic_type_sub_types
belongs_to :statistic_index
has_many :statistic_type_sub_types, dependent: :destroy
has_many :statistic_sub_types, through: :statistic_type_sub_types
has_many :statistic_custom_aggregations
has_many :statistic_custom_aggregations, dependent: :destroy
end
30 changes: 30 additions & 0 deletions app/services/excel_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

# Provides methods around Excel files specification
class ExcelService
class << self
# remove all unauthorized characters from the given Excel's worksheet name
# @param name [String]
# @param replace [String]
# @return [String]
def name_safe(name, replace = '-')
name.gsub(%r{[*|\\:"<>?/]}, replace).truncate(31)
end

# Generate a name for the current type, compatible with Excel worksheet names
# @param type [StatisticType]
# @param workbook [Axlsx::Workbook]
# @return [String]
def statistic_type_sheet_name(type, workbook)
# see https://msdn.microsoft.com/fr-fr/library/c6bdca6y(v=vs.90).aspx for unauthorized character list
name = "#{type.statistic_index.label} - #{type.label}".gsub(%r{[*|\\:"<>?/]}, '')
# sheet name is limited to 31 characters
if name.length > 31
name = "#{type.statistic_index.label.truncate(4, omission: '.')} - #{type.label}".gsub(%r{[*|\\:"<>?/]}, '').truncate(31)
end
# we cannot have two sheets with the same name
name = name[0..30] + String((rand * 10).to_i) until workbook.sheet_by_name(name).nil?
name
end
end
end
62 changes: 62 additions & 0 deletions app/services/invoices/number_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# frozen_string_literal: true

# module definition
module Invoices; end

# The invoice number is based on the previous invoice
class Invoices::NumberService
class << self
# Get the order number or reference number for the given invoice (not the whole identifier).
# The date part, online payment part, etc. will be excluded and only the number part will be returned.
# @param document [PaymentDocument,NilClass]
# @param setting [String] 'invoice_reference' | 'invoice_order-nb'
# @return [Integer,NilClass]
def number(document, setting = 'invoice_reference')
raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting)
return nil if document.nil?

saved_number = setting == 'invoice_reference' ? document.reference : document.order_number
return nil if saved_number.nil?

pattern = pattern(document, setting)
pattern = PaymentDocumentService.send(:replace_document_type_pattern, document, pattern)
start_idx = pattern.index(/n+|y+|m+|d+/)
end_idx = pattern.rindex(/n+|y+|m+|d+/)

saved_number[start_idx..end_idx]&.to_i
end

# @param document [PaymentDocument,NilClass]
# @param setting [String] 'invoice_reference' | 'invoice_order-nb'
# @return [String,NilClass] 'global' | 'year' | 'month' | 'day'
def number_periodicity(document, setting = 'invoice_reference')
raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting)
return nil if document.nil?

pattern = pattern(document, setting)
pattern = PaymentDocumentService.send(:replace_document_type_pattern, document, pattern)

return 'global' if pattern.match?(/n+/)
return 'year' if pattern.match?(/y+/)
return 'month' if pattern.match?(/m+/)
return 'day' if pattern.match?(/d+/)

nil
end

# Get the pattern applicable to generate the number of the given invoice.
# @param document [PaymentDocument]
# @param setting [String] 'invoice_reference' | 'invoice_order-nb'
# @return [String]
def pattern(document, setting = 'invoice_reference')
raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting)

value = Setting.find_by(name: setting).value_at(document.created_at)
value || if document.created_at < Setting.find_by(name: setting).first_update
Setting.find_by(name: setting).first_value
else
Setting.get(setting)
end
end
end
end
Loading

0 comments on commit 9683498

Please sign in to comment.