1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-20 14:54:15 +01:00

(bug) deal with DST using Time instead of DateTime

This commit is contained in:
Sylvain 2023-02-14 13:10:58 +01:00
parent dde6782475
commit 04f933f94d
63 changed files with 180 additions and 181 deletions

View File

@ -36,5 +36,9 @@ Style/FormatString:
EnforcedStyle: sprintf
Rails/RedundantPresenceValidationOnBelongsTo:
Enabled: false
Style/DateTime:
Enabled: true
Rails/TimeZone:
Enabled: true
Rails/UnknownEnv:
Environments: development, test, staging, production

View File

@ -1,14 +1,15 @@
# Changelog Fab-manager
- Use Time instead of DateTime objects
- Fix a bug: wrong times in admin/event monitoring
- Fix a bug: event update over daylight saving time's day results in wrong date
- Fix a bug: daylight saving time is ignored and result in wrong dates and/or times when dealing around the DST day
- Fix a bug: unable to run `rails db:seed` when first setup Fab-manager
## v5.6.11 2023 February 07
- OpenAPI endpoint to fetch subscription data
- Fix a bug: invalid date display in negative timezones
- Fix a bug: unable to get latest payment_gateway_object for plan/machine/training/space
- Fix a bug: unable to get the latest payment_gateway_object for plan/machine/training/space
## v5.6.10 2023 February 02

View File

@ -13,7 +13,7 @@ class API::AccountingPeriodsController < API::ApiController
def create
authorize AccountingPeriod
@accounting_period = AccountingPeriod.new(period_params.merge(closed_at: DateTime.current, closed_by: current_user.id))
@accounting_period = AccountingPeriod.new(period_params.merge(closed_at: Time.current, closed_by: current_user.id))
if @accounting_period.save
render :show, status: :created, location: @accounting_period
else

View File

@ -17,11 +17,11 @@ class API::EventsController < API::ApiController
if current_user&.admin? || current_user&.manager?
@events = case params[:scope]
when 'future'
@events.where('availabilities.start_at >= ?', DateTime.current).order('availabilities.start_at DESC')
@events.where('availabilities.start_at >= ?', Time.current).order('availabilities.start_at DESC')
when 'future_asc'
@events.where('availabilities.start_at >= ?', DateTime.current).order('availabilities.start_at ASC')
@events.where('availabilities.start_at >= ?', Time.current).order('availabilities.start_at ASC')
when 'passed'
@events.where('availabilities.start_at < ?', DateTime.current).order('availabilities.start_at DESC')
@events.where('availabilities.start_at < ?', Time.current).order('availabilities.start_at DESC')
else
@events.order('availabilities.start_at DESC')
end
@ -42,11 +42,11 @@ class API::EventsController < API::ApiController
@events = case Setting.get('upcoming_events_shown')
when 'until_start'
@events.where('availabilities.start_at >= ?', DateTime.current)
@events.where('availabilities.start_at >= ?', Time.current)
when '2h_before_end'
@events.where('availabilities.end_at >= ?', DateTime.current + 2.hours)
@events.where('availabilities.end_at >= ?', 2.hours.from_now)
else
@events.where('availabilities.end_at >= ?', DateTime.current)
@events.where('availabilities.end_at >= ?', Time.current)
end
end

View File

@ -11,7 +11,7 @@ class OpenAPI::V1::EventsController < OpenAPI::V1::BaseController
.where(deleted_at: nil)
@events = if upcoming
@events.references(:availabilities)
.where('availabilities.end_at >= ?', DateTime.current)
.where('availabilities.end_at >= ?', Time.current)
.order('availabilities.start_at ASC')
else
@events.order(created_at: :desc)

View File

@ -2,11 +2,10 @@
# RSS feed about 10 last events
class Rss::EventsController < Rss::RssController
def index
@events = Event.includes(:event_image, :event_files, :availability, :category)
.where('availabilities.start_at >= ?', DateTime.current)
.order('availabilities.start_at ASC').references(:availabilities).limit(10)
.where('availabilities.start_at >= ?', Time.current)
.order('availabilities.start_at').references(:availabilities).limit(10)
@fab_name = Setting.get('fablab_name')
end
end

View File

@ -65,19 +65,6 @@ module ApplicationHelper
amount / 100.00
end
##
# Apply a correction for a future DateTime due to change in Daylight Saving Time (DST) period
# @param reference {ActiveSupport::TimeWithZone}
# @param datetime {DateTime}
# Inspired by https://stackoverflow.com/a/12065605
##
def dst_correction(reference, datetime)
res = datetime.in_time_zone(reference.time_zone.tzinfo.name)
res -= 1.hour if res.dst? && !reference.dst?
res += 1.hour if reference.dst? && !res.dst?
res
end
# Return the given amount in centimes, without floating-point imprecision errors
def to_centimes(amount)
(BigDecimal(amount.to_s) * 100.0).to_f

View File

@ -60,7 +60,7 @@ module SingleSignOnConcern
# remove the token
self.auth_token = nil
self.merged_at = DateTime.current
self.merged_at = Time.current
# check that the email duplication was resolved
if sso_user.email.end_with? '-duplicate'

View File

@ -20,7 +20,7 @@ module UserRessourcesConcern
def next_training_reservation_by_machine(machine)
reservations.where(reservable_type: 'Training', reservable_id: machine.trainings.map(&:id))
.includes(:slots)
.where('slots.start_at>= ?', DateTime.current)
.where('slots.start_at>= ?', Time.current)
.order('slots.start_at': :asc)
.references(:slots)
.limit(1)
@ -28,7 +28,7 @@ module UserRessourcesConcern
end
def subscribed_plan
return nil if subscription.nil? || subscription.expired_at < DateTime.current
return nil if subscription.nil? || subscription.expired_at < Time.current
subscription.plan
end

View File

@ -2,16 +2,16 @@
# Coupon is a textual code associated with a discount rate or an amount of discount
class Coupon < ApplicationRecord
has_many :invoices
has_many :payment_schedule
has_many :orders
has_many :invoices, dependent: :nullify
has_many :payment_schedule, dependent: :nullify
has_many :orders, dependent: :nullify
after_create :create_gateway_coupon
before_destroy :delete_gateway_coupon
validates :name, presence: true
validates :code, presence: true
validates :code, format: { with: /\A[A-Z0-9\-]+\z/, message: 'only caps letters, numbers, and dashes' }
validates :code, format: { with: /\A[A-Z0-9\-]+\z/, message: I18n.t('coupon.invalid_format') }
validates :code, uniqueness: true
validates :validity_per_user, presence: true
validates :validity_per_user, inclusion: { in: %w[once forever] }
@ -19,7 +19,7 @@ class Coupon < ApplicationRecord
validates_with CouponExpirationValidator
scope :disabled, -> { where(active: false) }
scope :expired, -> { where('valid_until IS NOT NULL AND valid_until < ?', DateTime.current) }
scope :expired, -> { where('valid_until IS NOT NULL AND valid_until < ?', Time.current) }
scope :sold_out, lambda {
joins(:invoices).select('coupons.*, COUNT(invoices.id) as invoices_count').group('coupons.id')
.where.not(max_usages: nil).having('COUNT(invoices.id) >= coupons.max_usages')
@ -28,7 +28,7 @@ class Coupon < ApplicationRecord
joins('LEFT OUTER JOIN invoices ON invoices.coupon_id = coupons.id')
.select('coupons.*, COUNT(invoices.id) as invoices_count')
.group('coupons.id')
.where('active = true AND (valid_until IS NULL OR valid_until >= ?)', DateTime.current)
.where('active = true AND (valid_until IS NULL OR valid_until >= ?)', Time.current)
.having('COUNT(invoices.id) < coupons.max_usages OR coupons.max_usages IS NULL')
}
@ -61,7 +61,7 @@ class Coupon < ApplicationRecord
def status(user_id = nil, amount = nil)
if !active?
'disabled'
elsif !valid_until.nil? && valid_until.at_end_of_day < DateTime.current
elsif !valid_until.nil? && valid_until.at_end_of_day < Time.current
'expired'
elsif !max_usages.nil? && invoices.count >= max_usages
'sold_out'

View File

@ -49,7 +49,7 @@ class Event < ApplicationRecord
def recurrence_events
Event.includes(:availability)
.where('events.recurrence_id = ? AND events.id != ? AND availabilities.start_at >= ?', recurrence_id, id, DateTime.current)
.where('events.recurrence_id = ? AND events.id != ? AND availabilities.start_at >= ?', recurrence_id, id, Time.current)
.references(:availabilities)
end
@ -58,7 +58,7 @@ class Event < ApplicationRecord
end
def soft_destroy!
update(deleted_at: DateTime.current)
update(deleted_at: Time.current)
end
##

View File

@ -86,7 +86,7 @@ class Machine < ApplicationRecord
end
def soft_destroy!
update(deleted_at: DateTime.current)
update(deleted_at: Time.current)
end
def packs?(user)

View File

@ -20,7 +20,7 @@ class Order < PaymentDocument
delegate :user, to: :statistic_profile
def generate_reference(_date = DateTime.current)
def generate_reference(_date = Time.current)
self.reference = PaymentDocumentService.generate_order_number(self)
end

View File

@ -4,7 +4,7 @@
class PaymentDocument < Footprintable
self.abstract_class = true
def generate_reference(date = DateTime.current)
def generate_reference(date = Time.current)
self.reference = PaymentDocumentService.generate_reference(self, date: date)
end

View File

@ -88,7 +88,7 @@ class Project < ApplicationRecord
def after_save_and_publish
return unless saved_change_to_state? && published?
update_columns(published_at: DateTime.current)
update_columns(published_at: Time.current) # rubocop:disable Rails/SkipsModelValidations
notify_admin_when_project_published
end
end

View File

@ -70,7 +70,7 @@ class Space < ApplicationRecord
end
def soft_destroy!
update(deleted_at: DateTime.current)
update(deleted_at: Time.current)
end
private

View File

@ -26,7 +26,7 @@ class StatisticProfile < ApplicationRecord
has_many :trainings, through: :statistic_profile_trainings
# Projects that the current user is the author
has_many :my_projects, foreign_key: :author_statistic_profile_id, class_name: 'Project', dependent: :destroy
has_many :my_projects, foreign_key: :author_statistic_profile_id, class_name: 'Project', dependent: :destroy, inverse_of: :author
validate :check_birthday_in_past
@ -36,7 +36,7 @@ class StatisticProfile < ApplicationRecord
def age
if birthday.present?
now = DateTime.current.utc.to_date
now = Time.current.utc.to_date
(now - birthday).to_f / AVG_DAYS_PER_YEAR
else
''

View File

@ -16,6 +16,6 @@ class StatisticProfilePrepaidPack < ApplicationRecord
def set_expiration_date
return unless prepaid_pack.validity
self.expires_at = DateTime.current + prepaid_pack.validity
self.expires_at = Time.zone.now + prepaid_pack.validity
end
end

View File

@ -39,7 +39,7 @@ class Subscription < ApplicationRecord
end
def expired?
expired_at <= DateTime.current
expired_at <= Time.current
end
def expired_at
@ -108,7 +108,7 @@ class Subscription < ApplicationRecord
end
def set_expiration_date
start_at = self.start_at || DateTime.current.in_time_zone
start_at = self.start_at || Time.current
self.expiration_date = start_at + plan.duration
end

View File

@ -8,7 +8,7 @@ class EventPolicy < ApplicationPolicy
if user.nil? || (user && !user.admin? && !user.manager?)
scope.includes(:event_image, :event_files, :availability, :category, :event_price_categories, :age_range, :events_event_themes,
:event_themes)
.where('availabilities.start_at >= ?', DateTime.current)
.where('availabilities.start_at >= ?', Time.current)
.where(deleted_at: nil)
.order('availabilities.start_at ASC')
.references(:availabilities)

View File

@ -9,7 +9,7 @@ class SlotsReservationPolicy < ApplicationPolicy
# these condition does not apply to admins
user.admin? || user.manager? ||
(record.reservation.user == user && enabled && ((record.slot.start_at - DateTime.current).to_i / 3600 >= delay))
(record.reservation.user == user && enabled && ((record.slot.start_at - Time.current).to_i / 3600 >= delay))
end
def cancel?

View File

@ -80,7 +80,7 @@ class Availabilities::AvailabilitiesService
private
def subscription_year?(user)
user&.subscription && user.subscription.plan.interval == 'year' && user.subscription.expired_at >= DateTime.current
user&.subscription && user.subscription.plan.interval == 'year' && user.subscription.expired_at >= Time.current
end
# members must have validated at least 1 training and must have a valid yearly subscription to view

View File

@ -7,7 +7,7 @@ class Cart::AddItemService
raise Cart::InactiveProductError unless orderable.is_active
order.created_at = DateTime.current if order.order_items.length.zero?
order.created_at = Time.current if order.order_items.length.zero?
item = order.order_items.find_by(orderable: orderable)
quantity = orderable.quantity_min > quantity.to_i && item.nil? ? orderable.quantity_min : quantity.to_i

View File

@ -87,7 +87,7 @@ class CartService
plan
end
elsif @customer.subscribed_plan
subscription = @customer.subscription unless @customer.subscription.expired_at < DateTime.current
subscription = @customer.subscription unless @customer.subscription.expired_at < Time.current
@customer.subscribed_plan
else
nil

View File

@ -33,19 +33,15 @@ class Event::CreateEventService
private
def occurence_start_date(event, date)
start_at = DateTime.new(date.year, date.month, date.day,
event.availability.start_at.hour, event.availability.start_at.min, event.availability.start_at.sec,
event.availability.start_at.zone)
dst_correction(event.availability.start_at, start_at)
Time.zone.local(date.year, date.month, date.day,
event.availability.start_at.hour, event.availability.start_at.min, event.availability.start_at.sec)
end
def occurrence_end_date(event, date)
days_diff = event.availability.end_at.day - event.availability.start_at.day
end_date = date + days_diff.days
end_at = DateTime.new(end_date.year, end_date.month, end_date.day,
event.availability.end_at.hour, event.availability.end_at.min, event.availability.end_at.sec,
event.availability.end_at.zone)
dst_correction(event.availability.start_at, end_at)
Time.zone.local(end_date.year, end_date.month, end_date.day,
event.availability.end_at.hour, event.availability.end_at.min, event.availability.end_at.sec)
end
def occurrence_image(event)

View File

@ -53,7 +53,7 @@ class ExportService
Profile.where(user_id: User.members).maximum('updated_at'),
InvoicingProfile.where(user_id: User.members).maximum('updated_at'),
StatisticProfile.where(user_id: User.members).maximum('updated_at'),
Subscription.maximum('updated_at') || DateTime.current
Subscription.maximum('updated_at') || Time.current
].max
query_last_export('users', 'members', query, key, extension)

View File

@ -74,15 +74,15 @@ class HealthService
# availabilities for the last week
def self.last_week_availabilities
Availability.where('start_at >= ? AND end_at <= ?', DateTime.current - 7.days, DateTime.current).count
Availability.where('start_at >= ? AND end_at <= ?', 7.days.ago, Time.current).count
end
# reservations made during the last week
def self.last_week_new_reservations
Reservation.where('created_at >= ? AND created_at < ?', DateTime.current - 7.days, DateTime.current).count
Reservation.where('created_at >= ? AND created_at < ?', 7.days.ago, Time.current).count
end
def self.last_week_orders
Order.where('created_at >= ? AND created_at < ?', DateTime.current - 7.days, DateTime.current).where.not(state: 'cart').count
Order.where('created_at >= ? AND created_at < ?', 7.days.ago, Time.current).where.not(state: 'cart').count
end
end

View File

@ -76,7 +76,7 @@ class Members::MembersService
end
def validate(is_valid)
is_updated = member.update(validated_at: is_valid ? DateTime.current : nil)
is_updated = member.update(validated_at: is_valid ? Time.current : nil)
if is_updated
if is_valid
NotificationCenter.call type: 'notify_user_is_validated',

View File

@ -3,13 +3,14 @@
# Provides methods to generate Invoice, Avoir or PaymentSchedule references
class PaymentDocumentService
class << self
def generate_reference(document, date: DateTime.current)
def generate_reference(document, date: Time.current)
pattern = Setting.get('invoice_reference')
reference = replace_invoice_number_pattern(pattern, document.created_at)
reference = replace_date_pattern(reference, date)
if document.is_a? Avoir
case document
when Avoir
# information about refund/avoir (R[text])
reference.gsub!(/R\[([^\]]+)\]/, '\1')
@ -17,14 +18,14 @@ class PaymentDocumentService
reference.gsub!(/X\[([^\]]+)\]/, ''.to_s)
# remove information about payment schedule (S[text])
reference.gsub!(/S\[([^\]]+)\]/, ''.to_s)
elsif document.is_a? PaymentSchedule
when PaymentSchedule
# information about payment schedule
reference.gsub!(/S\[([^\]]+)\]/, '\1')
# remove information about online selling (X[text])
reference.gsub!(/X\[([^\]]+)\]/, ''.to_s)
# remove information about refunds (R[text])
reference.gsub!(/R\[([^\]]+)\]/, ''.to_s)
elsif document.is_a? Invoice
when Invoice
# information about online selling (X[text])
if document.paid_by_card?
reference.gsub!(/X\[([^\]]+)\]/, '\1')
@ -74,7 +75,7 @@ class PaymentDocumentService
# @param date {Date} the ending date
# @return {Integer}
##
def number_of_invoices(range, date = DateTime.current)
def number_of_invoices(range, date = Time.current)
case range.to_s
when 'day'
start = date.beginning_of_day

View File

@ -35,7 +35,7 @@ class PaymentScheduleService
def compute_deadline(deadline_index, payment_schedule, price_per_month, adjustment_price, other_items_price,
coupon: nil, schedule_start_at: nil)
date = (schedule_start_at || DateTime.current) + deadline_index.months
date = (schedule_start_at || Time.current) + deadline_index.months
details = { recurring: price_per_month }
amount = if deadline_index.zero?
details[:adjustment] = adjustment_price.truncate
@ -154,7 +154,7 @@ class PaymentScheduleService
unless filters[:date].nil?
ps = ps.where(
"date_trunc('day', payment_schedules.created_at) = :search OR date_trunc('day', payment_schedule_items.due_date) = :search",
search: "%#{DateTime.iso8601(filters[:date]).to_time.to_date}%"
search: "%#{Time.zone.iso8601(filters[:date]).to_date}%"
)
end
@ -176,7 +176,7 @@ class PaymentScheduleService
end
# cancel subscription
subscription = payment_schedule.payment_schedule_objects.find { |pso| pso.object_type == Subscription.name }.subscription
subscription.expire(DateTime.current)
subscription.expire(Time.current)
subscription.canceled_at
end
@ -196,7 +196,7 @@ class PaymentScheduleService
##
def reset_erroneous_payment_schedule_items(payment_schedule)
results = payment_schedule.payment_schedule_items.where(state: %w[error gateway_canceled]).map do |item|
item.update(state: item.due_date < DateTime.current ? 'pending' : 'new')
item.update(state: item.due_date < Time.current ? 'pending' : 'new')
end
results.reduce(true) { |acc, item| acc && item }
end

View File

@ -28,7 +28,7 @@ module Payments::PaymentConcern
payment_method
end
order.state = 'paid'
order.created_at = DateTime.current
order.created_at = Time.current
if payment_id && payment_type
order.payment_gateway_object = PaymentGatewayObject.new(gateway_object_id: payment_id, gateway_object_type: payment_type)
end

View File

@ -23,10 +23,10 @@ class PrepaidPackService
StatisticProfilePrepaidPack
.includes(:prepaid_pack)
.references(:prepaid_packs)
.where('statistic_profile_id = ?', user.statistic_profile.id)
.where('expires_at > ? OR expires_at IS NULL', DateTime.current)
.where('prepaid_packs.priceable_id = ?', priceable.id)
.where('prepaid_packs.priceable_type = ?', priceable.class.name)
.where(statistic_profile_id: user.statistic_profile.id)
.where('expires_at > ? OR expires_at IS NULL', Time.current)
.where(prepaid_packs: { priceable_id: priceable.id })
.where(prepaid_packs: { priceable_type: priceable.class.name })
.where('minutes_used < prepaid_packs.minutes')
end
@ -53,7 +53,7 @@ class PrepaidPackService
remaining = pack_available - consumed
remaining = 0 if remaining.negative?
pack_consumed = pack.prepaid_pack.minutes - remaining
pack.update_attributes(minutes_used: pack_consumed)
pack.update(minutes_used: pack_consumed)
consumed -= pack_consumed
end

View File

@ -46,7 +46,7 @@ class ProductService
remaining_stock[movement[:stock_type].to_sym] += quantity
{
stock_type: movement[:stock_type], reason: movement[:reason], quantity: quantity,
remaining_stock: remaining_stock[movement[:stock_type].to_sym], date: DateTime.current, order_item_id: movement[:order_item_id]
remaining_stock: remaining_stock[movement[:stock_type].to_sym], date: Time.current, order_item_id: movement[:order_item_id]
}
end || {}
product.stock = remaining_stock

View File

@ -74,7 +74,7 @@ class SettingService
def validate_admins(settings)
return unless settings.any? { |s| s.name == 'user_validation_required' && s.value == 'true' }
User.admins.each { |admin| admin.update(validated_at: DateTime.current) if admin.validated_at.nil? }
User.admins.each { |admin| admin.update(validated_at: Time.current) if admin.validated_at.nil? }
end
def update_accounting_line(settings)

View File

@ -5,7 +5,7 @@ class SlotsReservationsService
class << self
def cancel(slot_reservation)
# first we mark ths slot reservation as cancelled in DB, to free a ticket
slot_reservation.update_attributes(canceled_at: DateTime.current)
slot_reservation.update(canceled_at: Time.current)
# then we try to remove this reservation from ElasticSearch, to keep the statistics up-to-date
model_name = slot_reservation.reservation.reservable.class.name

View File

@ -20,7 +20,7 @@ class UserService
)
user.build_statistic_profile(
gender: true,
birthday: DateTime.current
birthday: Time.current
)
saved = user.save
@ -33,7 +33,7 @@ class UserService
def create_admin(params)
generated_password = SecurePassword.generate
admin = User.new(params.merge(password: generated_password, validated_at: DateTime.current))
admin = User.new(params.merge(password: generated_password, validated_at: Time.current))
admin.send :set_slug
# if the authentication is made through an SSO, generate a migration token

View File

@ -41,12 +41,12 @@ class VatHistoryService
# As a futur improvement, we should save the VAT rate for each invoice_item in the DB
def vat_history(vat_rate_type) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
chronology = []
end_date = DateTime.current
Setting.find_by(name: 'invoice_VAT-active').history_values.order(created_at: 'DESC').each do |v|
end_date = Time.current
Setting.find_by(name: 'invoice_VAT-active').history_values.order(created_at: :desc).each do |v|
chronology.push(start: v.created_at, end: end_date, enabled: v.value == 'true')
end_date = v.created_at
end
chronology.push(start: DateTime.new(0), end: end_date, enabled: false)
chronology.push(start: Time.zone.local(0), end: end_date, enabled: false)
# now chronology contains something like one of the following:
# - [{start: 0000-01-01, end: now, enabled: false}] => VAT was never enabled
# - [
@ -68,17 +68,17 @@ class VatHistoryService
# before the first VAT rate was defined for the given type, the general VAT rate is used
vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate')
.history_values.where('created_at < ?', first_vat_rate_by_type.created_at)
.order(created_at: 'ASC').to_a
.order(created_at: :asc).to_a
# after that, the VAT rate for the given type is used
vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}")
.history_values.where('created_at >= ?', first_vat_rate_by_type.created_at)
.order(created_at: 'ASC')
.order(created_at: :asc)
vat_rate_by_type.each do |rate|
if rate.value.blank? || rate.value == 'null' || rate.value == 'undefined' || rate.value == 'NaN'
# if, at some point in the history, a blank rate was set, the general VAT rate is used instead
vat_rate = Setting.find_by(name: 'invoice_VAT-rate')
.history_values.where('created_at < ?', rate.created_at)
.order(created_at: 'DESC')
.order(created_at: :desc)
.first
rate.value = vat_rate.value
end

View File

@ -6,12 +6,11 @@ class ClosedPeriodValidator < ActiveModel::Validator
date = if record.is_a?(Avoir)
record.avoir_date
else
DateTime.current
Time.current
end
AccountingPeriod.all.each do |period|
record.errors[:date] << I18n.t('errors.messages.in_closed_period') if date >= period.start_at && date <= period.end_at
record.errors.add(:date, I18n.t('errors.messages.in_closed_period')) if date >= period.start_at && date <= period.end_at
end
end
end

View File

@ -1,3 +1,6 @@
# frozen_string_literal: true
# Check that the expiration date of the given coupon is a valid value
class CouponExpirationValidator < ActiveModel::Validator
##
# @param record {Coupon}
@ -5,15 +8,11 @@ class CouponExpirationValidator < ActiveModel::Validator
def validate(record)
previous = record.valid_until_was
current = record.valid_until
return if current.blank?
unless current.blank?
if current.end_of_day < DateTime.current
record.errors[:valid_until] << I18n.t('errors.messages.cannot_be_in_the_past')
end
record.errors.add(:valid_until, I18n.t('errors.messages.cannot_be_in_the_past')) if current.end_of_day < Time.current
return unless previous.present? && current.end_of_day < previous.end_of_day
if !previous.blank? and current.end_of_day < previous.end_of_day
record.errors[:valid_until] << I18n.t('errors.messages.cannot_be_before_previous_value')
end
end
record.errors.add(:valid_until, I18n.t('errors.messages.cannot_be_before_previous_value'))
end
end
end

View File

@ -12,16 +12,16 @@ class AccountingWorker
def today
service = Accounting::AccountingService.new
start = DateTime.current.beginning_of_day
finish = DateTime.current.end_of_day
start = Time.current.beginning_of_day
finish = Time.current.end_of_day
ids = service.build(start, finish)
@performed = "today: #{start} -> #{finish}; invoices: #{ids}"
end
def yesterday
service = Accounting::AccountingService.new
start = DateTime.yesterday.beginning_of_day
finish = DateTime.yesterday.end_of_day
start = 1.day.ago.beginning_of_day
finish = 1.day.ago.end_of_day
ids = service.build(start, finish)
@performed = "yesterday: #{start} -> #{finish}; invoices: #{ids}"
end

View File

@ -15,7 +15,7 @@ class ArchiveWorker
last_archive_checksum = previous_file ? Integrity::Checksum.file(previous_file) : nil
json_data = to_json_archive(period, invoices, schedules, previous_file, last_archive_checksum)
current_archive_checksum = Integrity::Checksum.text(json_data)
date = DateTime.iso8601
date = Time.current.iso8601
chained = Integrity::Checksum.text("#{current_archive_checksum}#{last_archive_checksum}#{date}")
Zip::OutputStream.open(period.archive_file) do |io|
@ -48,7 +48,7 @@ class ArchiveWorker
last_archive_checksum: last_checksum,
previous_file: previous_file,
software_version: Version.current,
date: DateTime.current.iso8601
date: Time.current.iso8601
},
formats: [:json],
handlers: [:jbuilder]

View File

@ -10,7 +10,7 @@ class PaymentScheduleItemWorker
psi = PaymentScheduleItem.find(record_id)
check_item(psi)
else
PaymentScheduleItem.where.not(state: 'paid').where('due_date < ?', DateTime.current).each do |item|
PaymentScheduleItem.where.not(state: 'paid').where('due_date < ?', Time.current).each do |item|
check_item(item)
end
end

View File

@ -10,7 +10,7 @@ class PeriodStatisticsWorker
days = date_to_days(period)
Rails.logger.info "\n==> generating statistics for the last #{days} days <==\n"
if days.zero?
Statistics::BuilderService.generate_statistic(start_date: DateTime.current.beginning_of_day, end_date: DateTime.current.end_of_day)
Statistics::BuilderService.generate_statistic(start_date: Time.current.beginning_of_day, end_date: Time.current.end_of_day)
else
days.times.each do |i|
Statistics::BuilderService.generate_statistic(start_date: i.day.ago.beginning_of_day, end_date: i.day.ago.end_of_day)
@ -19,9 +19,15 @@ class PeriodStatisticsWorker
end
def date_to_days(value)
return value.to_i if number?(value)
date = Date.parse(value.to_s)
(DateTime.current.to_date - date).to_i
rescue ArgumentError
value.to_i
(Time.current.to_date - date).to_i
end
def number?(string)
true if Float(string)
rescue StandardError
false
end
end

View File

@ -12,7 +12,7 @@ class ReservationReminderWorker
delay = Setting.find_by(name: 'reminder_delay').try(:value).try(:to_i).try(:hours) || DEFAULT_REMINDER_DELAY
starting = DateTime.current.beginning_of_hour + delay
starting = Time.current.beginning_of_hour + delay
ending = starting + 1.hour
Reservation.joins(slots_reservations: :slot)

View File

@ -1,23 +1,26 @@
# frozen_string_literal: true
# Notify users about the expiration of their subscription
class SubscriptionExpireWorker
include Sidekiq::Worker
def perform(expire_in)
Subscription.where('expiration_date >= ?', DateTime.current.at_beginning_of_day).each do |s|
if (s.expired_at - expire_in.days).to_date == DateTime.current.to_date
if expire_in != 0
NotificationCenter.call type: 'notify_member_subscription_will_expire_in_7_days',
receiver: s.user,
attached_object: s
NotificationCenter.call type: 'notify_admin_subscription_will_expire_in_7_days',
receiver: User.admins_and_managers,
attached_object: s
else
Subscription.where('expiration_date >= ?', Time.current.at_beginning_of_day).each do |s|
if (s.expired_at - expire_in.days).to_date == Time.current.to_date
if expire_in.zero?
NotificationCenter.call type: 'notify_member_subscription_is_expired',
receiver: s.user,
attached_object: s
NotificationCenter.call type: 'notify_admin_subscription_is_expired',
receiver: User.admins_and_managers,
attached_object: s
else
NotificationCenter.call type: 'notify_member_subscription_will_expire_in_7_days',
receiver: s.user,
attached_object: s
NotificationCenter.call type: 'notify_admin_subscription_will_expire_in_7_days',
receiver: User.admins_and_managers,
attached_object: s
end
end
end

View File

@ -49,6 +49,8 @@ en:
gateway_amount_too_large: "Payments above %{AMOUNT} are not supported. Please order directly at the reception."
product_in_use: "This product have already been ordered"
slug_already_used: "is already used"
coupon:
invalid_format: "only caps letters, numbers, and dashes are allowed"
apipie:
api_documentation: "API Documentation"
code: "HTTP code"

View File

@ -52,7 +52,7 @@ class PayZen::Charge < PayZen::Client
##
def create_subscription(amount: 0,
currency: Setting.get('payzen_currency'),
effect_date: DateTime.current.iso8601,
effect_date: Time.current.iso8601,
payment_method_token: nil,
rrule: nil,
order_id: nil,
@ -69,4 +69,3 @@ class PayZen::Charge < PayZen::Client
initialAmountNumber: initial_amount_number)
end
end

View File

@ -28,7 +28,7 @@ class PayZen::Helper < Payment::Helper
def generate_ref(cart_items, customer)
require 'sha3'
content = { cart_items: cart_items, customer: customer }.to_json + DateTime.current.to_s
content = { cart_items: cart_items, customer: customer }.to_json + Time.current.iso8601
# It's safe to truncate a hash. See https://crypto.stackexchange.com/questions/74646/sha3-255-one-bit-less
SHA3::Digest.hexdigest(:sha224, content)[0...24]
end

View File

@ -10,7 +10,7 @@ module PayZen; end
## create remote objects on PayZen
class PayZen::Service < Payment::Service
def create_subscription(payment_schedule, order_id, *args)
def create_subscription(payment_schedule, order_id, *_args)
first_item = payment_schedule.ordered_items.first
order = PayZen::Order.new.get(order_id, operation_type: 'VERIFICATION')
@ -79,34 +79,35 @@ class PayZen::Service < Payment::Service
def process_payment_schedule_item(payment_schedule_item)
pz_subscription = payment_schedule_item.payment_schedule.gateway_subscription.retrieve
if pz_subscription['answer']['cancelDate'] && DateTime.parse(pz_subscription['answer']['cancelDate']) <= DateTime.current
if pz_subscription['answer']['cancelDate'] && Time.zone.parse(pz_subscription['answer']['cancelDate']) <= Time.current
# the subscription was canceled by the gateway => notify & update the status
notify_payment_schedule_gateway_canceled(payment_schedule_item)
payment_schedule_item.update_attributes(state: 'gateway_canceled')
payment_schedule_item.update(state: 'gateway_canceled')
return
end
pz_order = payment_schedule_item.payment_schedule.gateway_order.retrieve
transaction = pz_order['answer']['transactions'].last
return unless transaction_matches?(transaction, payment_schedule_item)
if transaction['status'] == 'PAID'
case transaction['status']
when 'PAID'
PaymentScheduleService.new.generate_invoice(payment_schedule_item,
payment_method: 'card',
payment_id: transaction['uuid'],
payment_type: 'PayZen::Transaction')
payment_schedule_item.update_attributes(state: 'paid', payment_method: 'card')
payment_schedule_item.update(state: 'paid', payment_method: 'card')
pgo = PaymentGatewayObject.find_or_initialize_by(item: payment_schedule_item)
pgo.gateway_object = PayZen::Item.new('PayZen::Transaction', transaction['uuid'])
pgo.save!
elsif transaction['status'] == 'RUNNING'
when 'RUNNING'
notify_payment_schedule_item_failed(payment_schedule_item)
payment_schedule_item.update_attributes(state: transaction['detailedStatus'])
payment_schedule_item.update(state: transaction['detailedStatus'])
pgo = PaymentGatewayObject.find_or_initialize_by(item: payment_schedule_item)
pgo.gateway_object = PayZen::Item.new('PayZen::Transaction', transaction['uuid'])
pgo.save!
else
notify_payment_schedule_item_error(payment_schedule_item)
payment_schedule_item.update_attributes(state: 'error')
payment_schedule_item.update(state: 'error')
end
end
@ -127,7 +128,7 @@ class PayZen::Service < Payment::Service
# check if the given transaction matches the given PaymentScheduleItem
def transaction_matches?(transaction, payment_schedule_item)
transaction_date = DateTime.parse(transaction['creationDate']).to_date
transaction_date = Time.zone.parse(transaction['creationDate']).to_date
transaction['amount'] == payment_schedule_item.amount &&
transaction_date >= payment_schedule_item.due_date.to_date &&

View File

@ -67,7 +67,12 @@ namespace :fablab do
desc '[release 2.5.14] fix times of recursive events that crosses DST periods'
task recursive_events_over_DST: :environment do
include ApplicationHelper
def dst_correction(reference, datetime)
res = datetime.in_time_zone(reference.time_zone.tzinfo.name)
res -= 1.hour if res.dst? && !reference.dst?
res += 1.hour if reference.dst? && !res.dst?
res
end
failed_ids = []
groups = Event.group(:recurrence_id).count
groups.each_key do |recurrent_event_id|
@ -129,7 +134,7 @@ namespace :fablab do
desc '[release 3.1.2] fix users with invalid group_id'
task users_group_ids: :environment do
User.where.not(group_id: Group.all.map(&:id)).each do |u|
u.update_columns(group_id: Group.first.id, updated_at: DateTime.current) # rubocop:disable Rails/SkipsModelValidations
u.update_columns(group_id: Group.first.id, updated_at: Time.current) # rubocop:disable Rails/SkipsModelValidations
meta_data = { ex_group_name: 'invalid group' }
@ -208,19 +213,19 @@ namespace :fablab do
desc '[release 5.4.24] fix prepaid pack hours dont count down after a reservation of machine'
task :prepaid_pack_count_down, %i[start_date end_date] => :environment do |_task, args|
# set start date to the date of deployment of v5.4.13 that product the bug
start_date = DateTime.parse('2022-07-28T10:00:00+02:00')
start_date = Time.zone.parse('2022-07-28T10:00:00+02:00')
if args.start_date
begin
start_date = DateTime.parse(args.start_date)
start_date = Time.zone.parse(args.start_date)
rescue ArgumentError => e
raise e
end
end
# set end date to the date of deployment of v5.4.24 after fix the bug
end_date = DateTime.parse('2022-10-14T18:40:00+02:00')
end_date = Time.zone.parse('2022-10-14T18:40:00+02:00')
if args.end_date
begin
end_date = DateTime.parse(args.end_date)
end_date = Time.zone.parse(args.end_date)
rescue ArgumentError => e
raise e
end

View File

@ -54,13 +54,13 @@ namespace :fablab do
slots_reservations_attributes: slots_reservations_attributes(invoice, reservable),
statistic_profile_id: StatisticProfile.find_by(user: invoice.user).id
)
invoice.update_attributes(invoiced: reservation)
invoice.update(invoiced: reservation)
else
warn "WARNING: Unable to guess the reservable for invoice #{invoice.id}, please handle manually."
warn 'Ignoring...'
end
when 'e'
invoice.update_attributes(invoiced_type: 'Error')
invoice.update(invoiced_type: 'Error')
else
puts "Operation #{confirm} unknown. Ignoring invoice #{invoice.id}..."
end
@ -99,12 +99,10 @@ namespace :fablab do
description = ii.description
# DateTime.parse only works with english dates, so translate the month name
month_idx = I18n.t('date.month_names').find_index { |month| month && description.include?(month) }
unless month_idx.nil?
description.gsub!(/#{I18n.t('date.month_names')[month_idx]}/, I18n.t('date.month_names', locale: :en)[month_idx])
end
start = DateTime.parse(description)
end_time = DateTime.parse(/- (.+)$/.match(description)[1])
[start, DateTime.new(start.year, start.month, start.day, end_time.hour, end_time.min, end_time.sec, DateTime.current.zone)]
description.gsub!(/#{I18n.t('date.month_names')[month_idx]}/, I18n.t('date.month_names', locale: :en)[month_idx]) unless month_idx.nil?
start = Time.zone.parse(description)
end_time = Time.zone.parse(/- (.+)$/.match(description)[1])
[start, Time.zone.local(start.year, start.month, start.day, end_time.hour, end_time.min, end_time.sec)]
end
end

View File

@ -76,8 +76,8 @@ class AccountingPeriodTest < ActionDispatch::IntegrationTest
end
test 'admin tries to close today' do
start_at = DateTime.current.beginning_of_day.iso8601
end_at = DateTime.current.end_of_day.iso8601
start_at = Time.current.beginning_of_day.iso8601
end_at = Time.current.end_of_day.iso8601
post '/api/accounting_periods',
params: {

View File

@ -19,7 +19,7 @@ class Exports::AccountingExportTest < ActionDispatch::IntegrationTest
encoding: 'ISO-8859-1',
date_format: '%d/%m/%Y',
start_date: '2012-03-12T00:00:00.000Z',
end_date: DateTime.current.utc.iso8601,
end_date: Time.current.utc.iso8601,
label_max_length: 50,
decimal_separator: ',',
export_invoices_at_zero: false
@ -121,7 +121,7 @@ class Exports::AccountingExportTest < ActionDispatch::IntegrationTest
def check_entry_date(invoice, line)
entry_date = invoice.created_at.to_date
assert_equal entry_date, DateTime.parse(line[I18n.t('accounting_export.date')]), 'Wrong date'
assert_equal entry_date, Time.zone.parse(line[I18n.t('accounting_export.date')]).to_date, 'Wrong date'
end
def check_client_accounts(invoice, client_line)

View File

@ -36,7 +36,7 @@ class InvoicesTest < ActionDispatch::IntegrationTest
end
test 'admin generates a refund' do
date = DateTime.current.iso8601
date = Time.current.iso8601
post '/api/invoices', params: { avoir: {
avoir_date: date,
@ -69,7 +69,7 @@ class InvoicesTest < ActionDispatch::IntegrationTest
end
test 'admin fails generates a refund in closed period' do
date = '2015-10-01T13:09:55+01:00'.to_datetime
date = Time.zone.parse('2015-10-01T13:09:55+01:00')
post '/api/invoices', params: { avoir: {
avoir_date: date,

View File

@ -49,7 +49,6 @@ class PayzenTest < ActionDispatch::IntegrationTest
assert_not_nil payment[:orderId]
end
test 'confirm payment with payzen' do
require 'pay_zen/helper'
require 'pay_zen/pci/charge'
@ -63,7 +62,6 @@ class PayzenTest < ActionDispatch::IntegrationTest
invoices_count = Invoice.count
slots_reservation_count = SlotsReservation.count
cart_items = {
items: [
{
@ -85,7 +83,6 @@ class PayzenTest < ActionDispatch::IntegrationTest
]
}
cs = CartService.new(@user)
cart = cs.from_hash(cart_items)
amount = cart.total[:total]
@ -112,7 +109,7 @@ class PayzenTest < ActionDispatch::IntegrationTest
paymentMethodType: 'CARD',
pan: '4970100000000055',
expiryMonth: 12,
expiryYear: DateTime.current.strftime('%y'),
expiryYear: Time.current.strftime('%y'),
securityCode: 123
}])

View File

@ -44,14 +44,14 @@ class Subscriptions::RenewAsUserTest < ActionDispatch::IntegrationTest
assert_not_nil @user.subscription, "user's subscription was not found"
# Check the expiration date
assert @user.subscription.expired_at > DateTime.current,
assert @user.subscription.expired_at > Time.current,
"user's subscription expiration was not updated ... VCR cassettes may be outdated, please check the gitlab wiki"
assert_equal @user.subscription.expired_at.iso8601,
(@user.subscription.created_at + plan.duration).iso8601,
'subscription expiration date does not match'
assert_in_delta 5,
(DateTime.current.to_i - @user.subscription.updated_at.to_i),
(Time.current.to_i - @user.subscription.updated_at.to_i),
10,
"user's subscription was not updated recently"

View File

@ -85,7 +85,7 @@ class WalletsTest < ActionDispatch::IntegrationTest
login_as(admin, scope: :user)
w = @vlonchamp.wallet
amount = 10
avoir_date = DateTime.current.end_of_day
avoir_date = Time.current.end_of_day
expected_amount = w.amount + amount
put "/api/wallet/#{w.id}/credit",
params: {

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'test_helper'
class StatisticProfilePrepaidPackTest < ActiveSupport::TestCase
@ -5,7 +7,7 @@ class StatisticProfilePrepaidPackTest < ActiveSupport::TestCase
prepaid_pack = PrepaidPack.first
user = User.find_by(username: 'jdupond')
p = StatisticProfilePrepaidPack.create!(prepaid_pack: prepaid_pack, statistic_profile: user.statistic_profile)
expires_at = DateTime.current + 12.months
expires_at = 12.months.from_now
assert p.expires_at.strftime('%Y-%m-%d'), expires_at.strftime('%Y-%m-%d')
end
end

View File

@ -14,7 +14,7 @@ class AvailabilitiesServiceTest < ActiveSupport::TestCase
test 'no machines availabilities during given window' do
service = Availabilities::AvailabilitiesService.new(@no_subscription)
slots = service.machines([Machine.find(3)], @no_subscription,
{ start: DateTime.current.beginning_of_day, end: 1.day.from_now.end_of_day })
{ start: Time.current.beginning_of_day, end: 1.day.from_now.end_of_day })
assert_empty slots
end
@ -30,7 +30,7 @@ class AvailabilitiesServiceTest < ActiveSupport::TestCase
test 'no past availabilities for members' do
service = Availabilities::AvailabilitiesService.new(@no_subscription)
slots = service.machines([Machine.find(2)], @no_subscription,
{ start: DateTime.parse('2015-06-15').beginning_of_day, end: DateTime.parse('2015-06-15').end_of_day })
{ start: Time.zone.parse('2015-06-15').beginning_of_day, end: Time.zone.parse('2015-06-15').end_of_day })
assert_empty slots
end
@ -38,7 +38,7 @@ class AvailabilitiesServiceTest < ActiveSupport::TestCase
test 'admin cannot see past availabilities further than 1 month' do
service = Availabilities::AvailabilitiesService.new(@admin)
slots = service.machines([Machine.find(2)], @no_subscription,
{ start: DateTime.parse('2015-06-15').beginning_of_day, end: DateTime.parse('2015-06-15').end_of_day })
{ start: Time.zone.parse('2015-06-15').beginning_of_day, end: Time.zone.parse('2015-06-15').end_of_day })
assert_empty slots
end
@ -80,10 +80,10 @@ class AvailabilitiesServiceTest < ActiveSupport::TestCase
test 'trainings availabilities' do
service = Availabilities::AvailabilitiesService.new(@no_subscription)
trainings = [Training.find(1), Training.find(2)]
slots = service.trainings(trainings, @no_subscription, { start: DateTime.current.beginning_of_day, end: 2.days.from_now.end_of_day })
slots = service.trainings(trainings, @no_subscription, { start: Time.current.beginning_of_day, end: 2.days.from_now.end_of_day })
assert_not_empty slots
if DateTime.current.hour >= 6
if Time.current.hour >= 6
assert_equal Availability.find(2).slots.count, slots.count
else
assert_equal Availability.find(1).slots.count + Availability.find(2).slots.count, slots.count
@ -93,7 +93,7 @@ class AvailabilitiesServiceTest < ActiveSupport::TestCase
test 'events availability' do
service = Availabilities::AvailabilitiesService.new(@no_subscription)
slots = service.events([Event.find(4)], @no_subscription,
{ start: DateTime.current.beginning_of_day, end: 30.days.from_now.end_of_day })
{ start: Time.current.beginning_of_day, end: 30.days.from_now.end_of_day })
assert_not_empty slots
availability = Availability.find(17)

View File

@ -97,7 +97,7 @@ class ReservationSubscriptionStatisticServiceTest < ActionDispatch::IntegrationT
# 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: 2.days.ago.beginning_of_day,
end_date: DateTime.current.end_of_day })
end_date: Time.current.end_of_day })
Stats::Machine.refresh_index!
@ -119,14 +119,14 @@ class ReservationSubscriptionStatisticServiceTest < ActionDispatch::IntegrationT
check_statistics_on_user(stat_hour)
# second machine reservation (today)
stat_booking = Stats::Machine.search(query: { bool: { must: [{ term: { date: DateTime.current.to_date.iso8601 } },
stat_booking = Stats::Machine.search(query: { bool: { must: [{ term: { date: Time.current.to_date.iso8601 } },
{ term: { type: 'booking' } }] } }).first
assert_not_nil stat_booking
assert_equal machine.friendly_id, stat_booking['subType']
assert_equal 1, stat_booking['stat']
check_statistics_on_user(stat_booking)
stat_hour = Stats::Machine.search(query: { bool: { must: [{ term: { date: DateTime.current.to_date.iso8601 } },
stat_hour = Stats::Machine.search(query: { bool: { must: [{ term: { date: Time.current.to_date.iso8601 } },
{ term: { type: 'hour' } }] } }).first
assert_not_nil stat_hour

View File

@ -9,13 +9,13 @@ class StoreStatisticServiceTest < ActionDispatch::IntegrationTest
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 })
::Statistics::BuilderService.generate_statistic({ start_date: Time.current.beginning_of_day,
end_date: Time.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 } },
stat_order = Stats::Order.search(query: { bool: { must: [{ term: { date: Time.current.to_date.iso8601 } },
{ term: { type: 'store' } }] } }).first
assert_not_nil stat_order
assert_equal @order.id, stat_order['orderId']

View File

@ -52,7 +52,7 @@ class ActiveSupport::TestCase
def stripe_payment_method(error: nil)
number = '4242424242424242'
exp_month = 4
exp_year = DateTime.current.next_year.year
exp_year = Time.current.next_year.year
cvc = '314'
case error

View File

@ -15,7 +15,7 @@ class AccountingWorkerTest < ActiveSupport::TestCase
end
test 'build accounting lines for yesterday by default' do
date = DateTime.current.midnight
date = Time.current.midnight
travel_to(date)
@worker.perform
assert_match(/^yesterday:/, @worker.performed)
@ -25,7 +25,7 @@ class AccountingWorkerTest < ActiveSupport::TestCase
test 'build accounting lines for today' do
@worker.perform(:today)
assert_match(/^today:/, @worker.performed)
assert_match(DateTime.current.to_date.iso8601, @worker.performed)
assert_match(Time.current.to_date.iso8601, @worker.performed)
end
test 'build specified invoices selection' do