mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-11-29 10:24:20 +01:00
refactor integrity checking code
This commit is contained in:
parent
3a910b1182
commit
5b7b54d421
92
lib/integrity/archive_helper.rb
Normal file
92
lib/integrity/archive_helper.rb
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Accounting integrity verifications
|
||||||
|
module Integrity; end
|
||||||
|
|
||||||
|
# Provides various helpers methods for interacting with accounting archives
|
||||||
|
class Integrity::ArchiveHelper
|
||||||
|
class << self
|
||||||
|
|
||||||
|
## Checks the validity of all closed periods and raise an error otherwise
|
||||||
|
def check_footprints
|
||||||
|
if AccountingPeriod.count.positive?
|
||||||
|
last_period = AccountingPeriod.order(start_at: :desc).first
|
||||||
|
puts "Checking invoices footprints from #{last_period.end_at}. This may take a while..."
|
||||||
|
Invoice.where('created_at > ?', last_period.end_at).order(:id).each do |i|
|
||||||
|
next if i.check_footprint
|
||||||
|
|
||||||
|
i.debug_footprint
|
||||||
|
raise "Invalid footprint for invoice #{i.id}"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts 'Checking all invoices footprints. This may take a while...'
|
||||||
|
Invoice.order(:id).all.each do |i|
|
||||||
|
next if i.check_footprint
|
||||||
|
|
||||||
|
i.debug_footprint
|
||||||
|
raise "Invalid footprint for invoice #{i.id}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# will return an array of hash containing the removed periods data
|
||||||
|
def backup_and_remove_periods(range_start: nil, range_end: nil)
|
||||||
|
range_periods = get_periods(range_start: range_start, range_end: range_end)
|
||||||
|
return [] unless range_periods.count.positive?
|
||||||
|
|
||||||
|
puts 'Removing accounting archives...'
|
||||||
|
# 1. remove protection for AccountingPeriods
|
||||||
|
execute("DROP RULE IF EXISTS accounting_periods_del_protect ON #{AccountingPeriod.arel_table.name};")
|
||||||
|
# 2. backup AccountingPeriods in memory
|
||||||
|
periods = []
|
||||||
|
range_periods.each do |p|
|
||||||
|
periods.push(
|
||||||
|
start_at: p.start_at,
|
||||||
|
end_at: p.end_at,
|
||||||
|
closed_at: p.closed_at,
|
||||||
|
closed_by: p.closed_by
|
||||||
|
)
|
||||||
|
end
|
||||||
|
# 3. Delete periods from database
|
||||||
|
range_periods.each do |ap|
|
||||||
|
execute("DELETE FROM accounting_periods WHERE ID=#{ap.id};")
|
||||||
|
end
|
||||||
|
periods
|
||||||
|
end
|
||||||
|
|
||||||
|
def restore_periods(periods)
|
||||||
|
return unless periods.size.positive?
|
||||||
|
|
||||||
|
# 1. recreate AccountingPeriods
|
||||||
|
puts 'Recreating accounting archives. This may take a while...'
|
||||||
|
periods.each do |p|
|
||||||
|
AccountingPeriod.create!(
|
||||||
|
start_at: p[:start_at],
|
||||||
|
end_at: p[:end_at],
|
||||||
|
closed_at: p[:closed_at],
|
||||||
|
closed_by: p[:closed_by]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
# 2. reset protection for AccountingPeriods
|
||||||
|
execute("CREATE RULE accounting_periods_del_protect AS ON DELETE TO #{AccountingPeriod.arel_table.name} DO INSTEAD NOTHING;")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def get_periods(range_start: nil, range_end: nil)
|
||||||
|
if range_start && range_end
|
||||||
|
AccountingPeriod.where('created_at > ? AND created_at < ?', range_start, range_end)
|
||||||
|
elsif range_start
|
||||||
|
AccountingPeriod.where('created_at > ?', range_start)
|
||||||
|
elsif range_end
|
||||||
|
AccountingPeriod.where('created_at < ?', range_end)
|
||||||
|
else
|
||||||
|
AccountingPeriod.all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute(query)
|
||||||
|
ActiveRecord::Base.connection.execute(query)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,5 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'integrity/archive_helper'
|
||||||
|
|
||||||
# This take will ensure data integrity for invoices.
|
# This take will ensure data integrity for invoices.
|
||||||
# A bug introduced with v4.3.0 has made invoices without saving the associated Reservation (Invoice.invoiced_id is null).
|
# A bug introduced with v4.3.0 has made invoices without saving the associated Reservation (Invoice.invoiced_id is null).
|
||||||
# This issue is concerning slots restricted to subscribers, when the restriction is manually overridden by an admin.
|
# This issue is concerning slots restricted to subscribers, when the restriction is manually overridden by an admin.
|
||||||
@ -11,9 +13,9 @@ namespace :fablab do
|
|||||||
include ActionView::Helpers::NumberHelper
|
include ActionView::Helpers::NumberHelper
|
||||||
|
|
||||||
# check the footprints and save the archives
|
# check the footprints and save the archives
|
||||||
check_footprints
|
Integrity::ArchiveHelper.check_footprints
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
periods = backup_and_remove_periods
|
periods = Integrity::ArchiveHelper.backup_and_remove_periods
|
||||||
|
|
||||||
# fix invoices data
|
# fix invoices data
|
||||||
Invoice.where(invoiced_id: nil).each do |invoice|
|
Invoice.where(invoiced_id: nil).each do |invoice|
|
||||||
@ -72,68 +74,12 @@ namespace :fablab do
|
|||||||
Invoice.order(:id).all.each(&:chain_record)
|
Invoice.order(:id).all.each(&:chain_record)
|
||||||
|
|
||||||
# re-create all archives from the memory dump
|
# re-create all archives from the memory dump
|
||||||
restore_periods(periods)
|
Integrity::ArchiveHelper.restore_periods(periods)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def check_footprints
|
|
||||||
if AccountingPeriod.count.positive?
|
|
||||||
last_period = AccountingPeriod.order(start_at: :desc).first
|
|
||||||
puts "Checking invoices footprints from #{last_period.end_at}. This may take a while..."
|
|
||||||
Invoice.where('created_at > ?', last_period.end_at).order(:id).each do |i|
|
|
||||||
raise "Invalid footprint for invoice #{i.id}" unless i.check_footprint
|
|
||||||
end
|
|
||||||
else
|
|
||||||
puts 'Checking all invoices footprints. This may take a while...'
|
|
||||||
Invoice.order(:id).all.each do |i|
|
|
||||||
raise "Invalid footprint for invoice #{i.id}" unless i.check_footprint
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# will return an array of hash containing the removed periods data
|
|
||||||
def backup_and_remove_periods
|
|
||||||
return [] unless AccountingPeriod.where("created_at > '2019-08-01' AND created_at < '2020-05-12'").count.positive?
|
|
||||||
|
|
||||||
puts 'Removing erroneous accounting archives...'
|
|
||||||
# 1. remove protection for AccountingPeriods
|
|
||||||
execute("DROP RULE IF EXISTS accounting_periods_del_protect ON #{AccountingPeriod.arel_table.name};")
|
|
||||||
# 2. backup AccountingPeriods in memory
|
|
||||||
periods = []
|
|
||||||
AccountingPeriod.where("created_at > '2019-08-01'").each do |p|
|
|
||||||
periods.push(
|
|
||||||
start_at: p.start_at,
|
|
||||||
end_at: p.end_at,
|
|
||||||
closed_at: p.closed_at,
|
|
||||||
closed_by: p.closed_by
|
|
||||||
)
|
|
||||||
end
|
|
||||||
# 3. Delete periods from database
|
|
||||||
AccountingPeriod.where("created_at > '2019-08-01'").each do |ap|
|
|
||||||
execute("DELETE FROM accounting_periods WHERE ID=#{ap.id};")
|
|
||||||
end
|
|
||||||
periods
|
|
||||||
end
|
|
||||||
|
|
||||||
def restore_periods(periods)
|
|
||||||
return unless periods.size.positive?
|
|
||||||
|
|
||||||
# 1. recreate AccountingPeriods
|
|
||||||
puts 'Recreating accounting archives. This may take a while...'
|
|
||||||
periods.each do |p|
|
|
||||||
AccountingPeriod.create!(
|
|
||||||
start_at: p[:start_at],
|
|
||||||
end_at: p[:end_at],
|
|
||||||
closed_at: p[:closed_at],
|
|
||||||
closed_by: p[:closed_by]
|
|
||||||
)
|
|
||||||
end
|
|
||||||
# 2. reset protection for AccountingPeriods
|
|
||||||
execute("CREATE RULE accounting_periods_del_protect AS ON DELETE TO #{AccountingPeriod.arel_table.name} DO INSTEAD NOTHING;")
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_reservable(invoice_item)
|
def find_reservable(invoice_item)
|
||||||
descr = /^([a-zA-Z\u00C0-\u017F]+\s+)+/.match(invoice_item.description)[0].strip[/(.*)\s/, 1]
|
descr = /^([a-zA-Z\u00C0-\u017F]+\s+)+/.match(invoice_item.description)[0].strip[/(.*)\s/, 1]
|
||||||
reservable = InvoiceItem.where('description LIKE ?', "#{descr}%")
|
reservable = InvoiceItem.where('description LIKE ?', "#{descr}%")
|
||||||
|
Loading…
Reference in New Issue
Block a user