From 7868f31a58a8087538eb08e05665fa9ee1993970 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 10 Nov 2022 16:14:49 +0100 Subject: [PATCH] (feat) advanced accounting parameters for: machines, spaces, trainings, events --- app/controllers/api/events_controller.rb | 11 +- app/controllers/api/machines_controller.rb | 3 +- app/controllers/api/spaces_controller.rb | 3 +- app/controllers/api/trainings_controller.rb | 3 +- .../accounting/advanced-accounting-form.tsx | 39 +++++ .../components/events/event-form.tsx | 2 + .../components/machines/machine-form.tsx | 2 + .../components/spaces/space-form.tsx | 2 + .../components/trainings/training-form.tsx | 2 + app/frontend/src/javascript/lib/format.ts | 2 +- .../javascript/models/advanced-accounting.ts | 5 + app/frontend/src/javascript/models/event.ts | 4 +- app/frontend/src/javascript/models/machine.ts | 13 +- app/frontend/src/javascript/models/setting.ts | 3 +- app/frontend/src/javascript/models/space.ts | 4 +- .../src/javascript/models/training.ts | 4 +- app/models/advanced_accounting.rb | 10 ++ app/models/event.rb | 72 ++------- app/models/events_event_theme.rb | 8 + app/models/machine.rb | 17 ++- app/models/payment_gateway_object.rb | 22 +-- app/models/payment_schedule.rb | 6 +- app/models/payment_schedule_object.rb | 9 +- app/models/projects_space.rb | 8 + app/models/setting.rb | 3 +- app/models/space.rb | 25 ++-- app/models/training.rb | 23 +-- app/services/event/create_event_service.rb | 64 ++++++++ app/services/event/update_event_service.rb | 141 ++++++++++++++++++ app/services/event_service.rb | 135 ----------------- .../_advanced_accounting.json.jbuilder | 3 + app/views/api/events/_event.json.jbuilder | 5 + app/views/api/machines/_machine.json.jbuilder | 6 + app/views/api/spaces/_space.json.jbuilder | 6 + .../api/trainings/_training.json.jbuilder | 6 + config/locales/app.admin.en.yml | 4 + config/locales/en.yml | 1 + ...21110120338_create_advanced_accountings.rb | 15 ++ db/schema.rb | 30 ++-- db/seeds.rb | 2 + 40 files changed, 451 insertions(+), 272 deletions(-) create mode 100644 app/frontend/src/javascript/components/accounting/advanced-accounting-form.tsx create mode 100644 app/frontend/src/javascript/models/advanced-accounting.ts create mode 100644 app/models/advanced_accounting.rb create mode 100644 app/models/events_event_theme.rb create mode 100644 app/models/projects_space.rb create mode 100644 app/services/event/create_event_service.rb create mode 100644 app/services/event/update_event_service.rb create mode 100644 app/views/api/advanced_accounting/_advanced_accounting.json.jbuilder create mode 100644 db/migrate/20221110120338_create_advanced_accountings.rb diff --git a/app/controllers/api/events_controller.rb b/app/controllers/api/events_controller.rb index 26f7300e0..12ccbf2c8 100644 --- a/app/controllers/api/events_controller.rb +++ b/app/controllers/api/events_controller.rb @@ -10,9 +10,9 @@ class API::EventsController < API::ApiController @scope = params[:scope] # filters - @events = @events.joins(:category).where('categories.id = :category', category: params[:category_id]) if params[:category_id] - @events = @events.joins(:event_themes).where('event_themes.id = :theme', theme: params[:theme_id]) if params[:theme_id] - @events = @events.where('age_range_id = :age_range', age_range: params[:age_range_id]) if params[:age_range_id] + @events = @events.joins(:category).where(categories: { id: params[:category_id] }) if params[:category_id] + @events = @events.joins(:event_themes).where(event_themes: { id: params[:theme_id] }) if params[:theme_id] + @events = @events.where(age_range_id: params[:age_range_id]) if params[:age_range_id] if current_user&.admin? || current_user&.manager? @events = case params[:scope] @@ -65,7 +65,7 @@ class API::EventsController < API::ApiController def update authorize Event - res = EventService.update(@event, event_params.permit!, params[:edit_mode]) + res = Event::UpdateEventService.update(@event, event_params.permit!, params[:edit_mode]) render json: { action: 'update', total: res[:events].length, updated: res[:events].select { |r| r[:status] }.length, details: res }, status: :ok, location: @event @@ -97,7 +97,8 @@ class API::EventsController < API::ApiController event_theme_ids: [], event_image_attributes: [:attachment], event_files_attributes: %i[id attachment _destroy], - event_price_categories_attributes: %i[id price_category_id amount _destroy]) + event_price_categories_attributes: %i[id price_category_id amount _destroy], + advanced_accounting_attributes: %i[code analytical_section]) EventService.process_params(event_preparams) end end diff --git a/app/controllers/api/machines_controller.rb b/app/controllers/api/machines_controller.rb index 810f08b4a..0db70d794 100644 --- a/app/controllers/api/machines_controller.rb +++ b/app/controllers/api/machines_controller.rb @@ -51,6 +51,7 @@ class API::MachinesController < API::ApiController def machine_params params.require(:machine).permit(:name, :description, :spec, :disabled, :plan_ids, plan_ids: [], machine_image_attributes: [:attachment], - machine_files_attributes: %i[id attachment _destroy]) + machine_files_attributes: %i[id attachment _destroy], + advanced_accounting_attributes: %i[code analytical_section]) end end diff --git a/app/controllers/api/spaces_controller.rb b/app/controllers/api/spaces_controller.rb index 287e6a19e..4945ddb44 100644 --- a/app/controllers/api/spaces_controller.rb +++ b/app/controllers/api/spaces_controller.rb @@ -51,6 +51,7 @@ class API::SpacesController < API::ApiController def space_params params.require(:space).permit(:name, :description, :characteristics, :default_places, :disabled, space_image_attributes: [:attachment], - space_files_attributes: %i[id attachment _destroy]) + space_files_attributes: %i[id attachment _destroy], + advanced_accounting_attributes: %i[code analytical_section]) end end diff --git a/app/controllers/api/trainings_controller.rb b/app/controllers/api/trainings_controller.rb index 83240a232..ba7e78325 100644 --- a/app/controllers/api/trainings_controller.rb +++ b/app/controllers/api/trainings_controller.rb @@ -76,6 +76,7 @@ class API::TrainingsController < API::ApiController def training_params params.require(:training) .permit(:id, :name, :description, :machine_ids, :plan_ids, :nb_total_places, :public_page, :disabled, - training_image_attributes: [:attachment], machine_ids: [], plan_ids: []) + training_image_attributes: [:attachment], machine_ids: [], plan_ids: [], + advanced_accounting_attributes: %i[code analytical_section]) end end diff --git a/app/frontend/src/javascript/components/accounting/advanced-accounting-form.tsx b/app/frontend/src/javascript/components/accounting/advanced-accounting-form.tsx new file mode 100644 index 000000000..3ead087ea --- /dev/null +++ b/app/frontend/src/javascript/components/accounting/advanced-accounting-form.tsx @@ -0,0 +1,39 @@ +import React, { useEffect, useState } from 'react'; +import SettingAPI from '../../api/setting'; +import { UseFormRegister } from 'react-hook-form'; +import { FieldValues } from 'react-hook-form/dist/types/fields'; +import { FormInput } from '../form/form-input'; +import { useTranslation } from 'react-i18next'; + +interface AdvancedAccountingFormProps { + register: UseFormRegister, + onError: (message: string) => void +} + +/** + * This component is a partial form, to be included in a resource form managed by react-hook-form. + * It will add advanced accounting attributes to the parent form, if they are enabled + */ +export const AdvancedAccountingForm = ({ register, onError }: AdvancedAccountingFormProps) => { + const [isEnabled, setIsEnabled] = useState(false); + + const { t } = useTranslation('admin'); + + useEffect(() => { + SettingAPI.get('advanced_accounting').then(res => setIsEnabled(res.value === 'true')).catch(onError); + }, []); + + return ( +
+ {isEnabled &&
+

{t('app.admin.advanced_accounting_form.title')}

+ + +
} +
+ ); +}; diff --git a/app/frontend/src/javascript/components/events/event-form.tsx b/app/frontend/src/javascript/components/events/event-form.tsx index 46c60176c..e22187765 100644 --- a/app/frontend/src/javascript/components/events/event-form.tsx +++ b/app/frontend/src/javascript/components/events/event-form.tsx @@ -23,6 +23,7 @@ import { Plus, Trash } from 'phosphor-react'; import FormatLib from '../../lib/format'; import EventPriceCategoryAPI from '../../api/event-price-category'; import { UpdateRecurrentModal } from './update-recurrent-modal'; +import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form'; declare const Application: IApplication; @@ -290,6 +291,7 @@ export const EventForm: React.FC = ({ action, event, onError, on id="event_files_attributes" className="event-files" /> + {t('app.admin.event_form.ACTION_event', { ACTION: action })} diff --git a/app/frontend/src/javascript/components/machines/machine-form.tsx b/app/frontend/src/javascript/components/machines/machine-form.tsx index 0157ba5fb..405632166 100644 --- a/app/frontend/src/javascript/components/machines/machine-form.tsx +++ b/app/frontend/src/javascript/components/machines/machine-form.tsx @@ -13,6 +13,7 @@ import { FormRichText } from '../form/form-rich-text'; import { FormSwitch } from '../form/form-switch'; import { FormMultiFileUpload } from '../form/form-multi-file-upload'; import { FabButton } from '../base/fab-button'; +import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form'; declare const Application: IApplication; @@ -86,6 +87,7 @@ export const MachineForm: React.FC = ({ action, machine, onErr id="disabled" label={t('app.admin.machine_form.disable_machine')} tooltip={t('app.admin.machine_form.disabled_help')} /> + {t('app.admin.machine_form.ACTION_machine', { ACTION: action })} diff --git a/app/frontend/src/javascript/components/spaces/space-form.tsx b/app/frontend/src/javascript/components/spaces/space-form.tsx index bc26323c5..16ffabd70 100644 --- a/app/frontend/src/javascript/components/spaces/space-form.tsx +++ b/app/frontend/src/javascript/components/spaces/space-form.tsx @@ -13,6 +13,7 @@ import { FormSwitch } from '../form/form-switch'; import { FormMultiFileUpload } from '../form/form-multi-file-upload'; import { FabButton } from '../base/fab-button'; import { Space } from '../../models/space'; +import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form'; declare const Application: IApplication; @@ -91,6 +92,7 @@ export const SpaceForm: React.FC = ({ action, space, onError, on id="disabled" label={t('app.admin.space_form.disable_space')} tooltip={t('app.admin.space_form.disabled_help')} /> + {t('app.admin.space_form.ACTION_space', { ACTION: action })} diff --git a/app/frontend/src/javascript/components/trainings/training-form.tsx b/app/frontend/src/javascript/components/trainings/training-form.tsx index d3f9bba7d..6d359a02b 100644 --- a/app/frontend/src/javascript/components/trainings/training-form.tsx +++ b/app/frontend/src/javascript/components/trainings/training-form.tsx @@ -18,6 +18,7 @@ import { Machine } from '../../models/machine'; import { SelectOption } from '../../models/select'; import SettingAPI from '../../api/setting'; import { Setting } from '../../models/setting'; +import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form'; declare const Application: IApplication; @@ -110,6 +111,7 @@ export const TrainingForm: React.FC = ({ action, training, on id="disabled" label={t('app.admin.training_form.disable_training')} tooltip={t('app.admin.training_form.disabled_help')} /> + {t('app.admin.training_form.ACTION_training', { ACTION: action })} diff --git a/app/frontend/src/javascript/lib/format.ts b/app/frontend/src/javascript/lib/format.ts index 1e6299ab7..ddf199aeb 100644 --- a/app/frontend/src/javascript/lib/format.ts +++ b/app/frontend/src/javascript/lib/format.ts @@ -17,7 +17,7 @@ export default class FormatLib { */ static time = (date: Date|TDateISO|`${THours}:${TMinutes}`): string => { let tempDate: Date; - const isoTimeMatch = (date as string).match(/^(\d\d):(\d\d)$/); + const isoTimeMatch = (date as string)?.match(/^(\d\d):(\d\d)$/); if (isoTimeMatch) { tempDate = new Date(); tempDate.setHours(parseInt(isoTimeMatch[1], 10)); diff --git a/app/frontend/src/javascript/models/advanced-accounting.ts b/app/frontend/src/javascript/models/advanced-accounting.ts new file mode 100644 index 000000000..0e3f42844 --- /dev/null +++ b/app/frontend/src/javascript/models/advanced-accounting.ts @@ -0,0 +1,5 @@ +export interface AdvancedAccounting { + id?: number, + code?: string, + analytical_section?: string +} diff --git a/app/frontend/src/javascript/models/event.ts b/app/frontend/src/javascript/models/event.ts index bf34dadfd..5e4fe83b5 100644 --- a/app/frontend/src/javascript/models/event.ts +++ b/app/frontend/src/javascript/models/event.ts @@ -1,5 +1,6 @@ import { TDateISO, TDateISODate, THours, TMinutes } from '../typings/date-iso'; import { FileType } from './file'; +import { AdvancedAccounting } from './advanced-accounting'; export interface EventPriceCategoryAttributes { id?: number, @@ -61,7 +62,8 @@ export interface Event { availability_id: number }>, recurrence: RecurrenceOption, - recurrence_end_at: Date + recurrence_end_at: Date, + advanced_accounting_attributes?: AdvancedAccounting } export interface EventDecoration { diff --git a/app/frontend/src/javascript/models/machine.ts b/app/frontend/src/javascript/models/machine.ts index da506c0d7..3bbe432b0 100644 --- a/app/frontend/src/javascript/models/machine.ts +++ b/app/frontend/src/javascript/models/machine.ts @@ -1,5 +1,7 @@ import { Reservation } from './reservation'; import { ApiFilter } from './api'; +import { FileType } from './file'; +import { AdvancedAccounting } from './advanced-accounting'; export interface MachineIndexFilter extends ApiFilter { disabled: boolean, @@ -12,12 +14,8 @@ export interface Machine { spec?: string, disabled: boolean, slug: string, - machine_image: string, - machine_files_attributes?: Array<{ - id: number, - attachment: string, - attachment_url: string - }>, + machine_image_attributes: FileType, + machine_files_attributes?: Array, trainings?: Array<{ id: number, name: string, @@ -31,5 +29,6 @@ export interface Machine { id: number, name: string, slug: string, - }> + }>, + advanced_accounting_attributes?: AdvancedAccounting } diff --git a/app/frontend/src/javascript/models/setting.ts b/app/frontend/src/javascript/models/setting.ts index 95e6d54b7..9610688dc 100644 --- a/app/frontend/src/javascript/models/setting.ts +++ b/app/frontend/src/javascript/models/setting.ts @@ -118,7 +118,8 @@ export const accountingSettings = [ 'accounting_Space_code', 'accounting_Space_label', 'accounting_Product_code', - 'accounting_Product_label' + 'accounting_Product_label', + 'advanced_accounting' ] as const; export const modulesSettings = [ diff --git a/app/frontend/src/javascript/models/space.ts b/app/frontend/src/javascript/models/space.ts index 0a73963ba..973540b44 100644 --- a/app/frontend/src/javascript/models/space.ts +++ b/app/frontend/src/javascript/models/space.ts @@ -1,4 +1,5 @@ import { FileType } from './file'; +import { AdvancedAccounting } from './advanced-accounting'; export interface Space { id: number, @@ -8,5 +9,6 @@ export interface Space { default_places: number, disabled: boolean, space_image_attributes: FileType, - space_file_attributes?: Array + space_file_attributes?: Array, + advanced_accounting_attributes?: AdvancedAccounting } diff --git a/app/frontend/src/javascript/models/training.ts b/app/frontend/src/javascript/models/training.ts index 45f3fc916..4b6948a88 100644 --- a/app/frontend/src/javascript/models/training.ts +++ b/app/frontend/src/javascript/models/training.ts @@ -1,6 +1,7 @@ import { ApiFilter } from './api'; import { TDateISO } from '../typings/date-iso'; import { FileType } from './file'; +import { AdvancedAccounting } from './advanced-accounting'; export interface Training { id?: number, @@ -22,7 +23,8 @@ export interface Training { full_name: string, is_valid: boolean }> - }> + }>, + advanced_accounting_attributes?: AdvancedAccounting } export interface TrainingIndexFilter extends ApiFilter { diff --git a/app/models/advanced_accounting.rb b/app/models/advanced_accounting.rb new file mode 100644 index 000000000..e56015812 --- /dev/null +++ b/app/models/advanced_accounting.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# AdvancedAccounting enables the various objects to have detailed accounting settings +class AdvancedAccounting < ApplicationRecord + belongs_to :accountable, polymorphic: true + belongs_to :machine, foreign_type: 'Machine', foreign_key: 'accountable_id', inverse_of: :advanced_accounting + belongs_to :training, foreign_type: 'Training', foreign_key: 'accountable_id', inverse_of: :advanced_accounting + belongs_to :space, foreign_type: 'Space', foreign_key: 'accountable_id', inverse_of: :advanced_accounting + belongs_to :event, foreign_type: 'event', foreign_key: 'accountable_id', inverse_of: :advanced_accounting +end diff --git a/app/models/event.rb b/app/models/event.rb index 3a75b6f27..b14a22aca 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -7,12 +7,17 @@ class Event < ApplicationRecord has_one :event_image, as: :viewable, dependent: :destroy accepts_nested_attributes_for :event_image, allow_destroy: true + has_many :event_files, as: :viewable, dependent: :destroy accepts_nested_attributes_for :event_files, allow_destroy: true, reject_if: :all_blank + belongs_to :category validates :category, presence: true + has_many :reservations, as: :reservable, dependent: :destroy - has_and_belongs_to_many :event_themes, join_table: 'events_event_themes', dependent: :destroy + + has_many :events_event_themes, dependent: :destroy + has_many :event_themes, through: :events_event_themes has_many :event_price_categories, dependent: :destroy has_many :price_categories, through: :event_price_categories @@ -23,12 +28,16 @@ class Event < ApplicationRecord belongs_to :availability, dependent: :destroy accepts_nested_attributes_for :availability + has_one :advanced_accounting, as: :accountable, dependent: :destroy + accepts_nested_attributes_for :advanced_accounting, allow_destroy: true + attr_accessor :recurrence, :recurrence_end_at before_save :update_nb_free_places after_create :event_recurrence + # update event updated_at for index cache - after_save -> { touch } + after_save -> { touch } # rubocop:disable Rails/SkipsModelValidations def name title @@ -71,10 +80,6 @@ class Event < ApplicationRecord end end - # def reservations - # Reservation.where(reservable: self) - # end - def update_nb_free_places if nb_total_places.nil? self.nb_free_places = nil @@ -97,8 +102,6 @@ class Event < ApplicationRecord return unless recurrence.present? && recurrence != 'none' on = case recurrence - when 'day' - nil when 'week' availability.start_at.wday when 'month' @@ -108,58 +111,11 @@ class Event < ApplicationRecord else nil end + r = Recurrence.new(every: recurrence, on: on, starts: availability.start_at + 1.day, until: recurrence_end_at) - service = Availabilities::CreateAvailabilitiesService.new r.events.each do |date| - days_diff = availability.end_at.day - availability.start_at.day - start_at = DateTime.new( - date.year, - date.month, - date.day, - availability.start_at.hour, - availability.start_at.min, - availability.start_at.sec, - availability.start_at.zone - ) - start_at = dst_correction(availability.start_at, start_at) - end_date = date + days_diff.days - end_at = DateTime.new( - end_date.year, - end_date.month, - end_date.day, - availability.end_at.hour, - availability.end_at.min, - availability.end_at.sec, - availability.end_at.zone - ) - end_at = dst_correction(availability.start_at, end_at) - ei = EventImage.new(attachment: event_image.attachment) if event_image - efs = event_files.map do |f| - EventFile.new(attachment: f.attachment) - end - event_price_cats = [] - event_price_categories.each do |epc| - event_price_cats.push(EventPriceCategory.new(price_category_id: epc.price_category_id, amount: epc.amount)) - end - event = Event.new( - recurrence: 'none', - title: title, - description: description, - event_image: ei, - event_files: efs, - availability: Availability.new(start_at: start_at, end_at: end_at, available_type: 'event'), - availability_id: nil, - category_id: category_id, - age_range_id: age_range_id, - event_themes: event_themes, - amount: amount, - event_price_categories: event_price_cats, - nb_total_places: nb_total_places, - recurrence_id: id - ) - event.save - service.create_slots(event.availability) + Event::CreateEventService.create_occurence(event, date) end - update_columns(recurrence_id: id) + update(recurrence_id: id) end end diff --git a/app/models/events_event_theme.rb b/app/models/events_event_theme.rb new file mode 100644 index 000000000..3902be542 --- /dev/null +++ b/app/models/events_event_theme.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# EventsEventTheme is the relation table between an Event and an EventTheme +# => theme associated with an Event +class EventsEventTheme < ApplicationRecord + belongs_to :event + belongs_to :event_theme +end diff --git a/app/models/machine.rb b/app/models/machine.rb index 0abd5e1c3..d26d2e0e2 100644 --- a/app/models/machine.rb +++ b/app/models/machine.rb @@ -34,6 +34,9 @@ class Machine < ApplicationRecord has_many :machines_products, dependent: :destroy has_many :products, through: :machines_products + has_one :advanced_accounting, as: :accountable, dependent: :destroy + accepts_nested_attributes_for :advanced_accounting, allow_destroy: true + after_create :create_statistic_subtype after_create :create_machine_prices after_create :update_gateway_product @@ -50,21 +53,19 @@ class Machine < ApplicationRecord end def create_statistic_subtype - index = StatisticIndex.where(es_type_key: 'machine') - StatisticSubType.create!(statistic_types: index.first.statistic_types, key: slug, label: name) + index = StatisticIndex.find_by(es_type_key: 'machine') + StatisticSubType.create!(statistic_types: index.statistic_types, key: slug, label: name) end def update_statistic_subtype - index = StatisticIndex.where(es_type_key: 'machine') + index = StatisticIndex.find_by(es_type_key: 'machine') subtype = StatisticSubType.joins(statistic_type_sub_types: :statistic_type) - .where(key: slug, statistic_types: { statistic_index_id: index.first.id }) - .first - subtype.label = name - subtype.save! + .find_by(key: slug, statistic_types: { statistic_index_id: index.id }) + subtype.update(label: name) end def remove_statistic_subtype - subtype = StatisticSubType.where(key: slug).first + subtype = StatisticSubType.find_by(key: slug) subtype.destroy! end diff --git a/app/models/payment_gateway_object.rb b/app/models/payment_gateway_object.rb index fa3ef7f58..24862f031 100644 --- a/app/models/payment_gateway_object.rb +++ b/app/models/payment_gateway_object.rb @@ -5,17 +5,17 @@ require 'payment/item_builder' # A link between an object in the local database and another object in the remote payment gateway database class PaymentGatewayObject < ApplicationRecord belongs_to :item, polymorphic: true - belongs_to :invoice, foreign_type: 'Invoice', foreign_key: 'item_id' - belongs_to :invoice_item, foreign_type: 'InvoiceItem', foreign_key: 'item_id' - belongs_to :subscription, foreign_type: 'Subscription', foreign_key: 'item_id' - belongs_to :payment_schedule, foreign_type: 'PaymentSchedule', foreign_key: 'item_id' - belongs_to :payment_schedule_item, foreign_type: 'PaymentScheduleItem', foreign_key: 'item_id' - belongs_to :user, foreign_type: 'User', foreign_key: 'item_id' - belongs_to :plan, foreign_type: 'Plan', foreign_key: 'item_id' - belongs_to :machine, foreign_type: 'Machine', foreign_key: 'item_id' - belongs_to :space, foreign_type: 'Space', foreign_key: 'item_id' - belongs_to :training, foreign_type: 'Training', foreign_key: 'item_id' - belongs_to :order, foreign_type: 'Order', foreign_key: 'item_id' + belongs_to :invoice, foreign_type: 'Invoice', foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :invoice_item, foreign_type: 'InvoiceItem', foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :subscription, foreign_type: 'Subscription', foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :payment_schedule, foreign_type: 'PaymentSchedule', foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :payment_schedule_item, foreign_type: 'PaymentScheduleItem', foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :user, foreign_type: 'User', foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :plan, foreign_type: 'Plan', foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :machine, foreign_type: 'Machine', foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :space, foreign_type: 'Space', foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :training, foreign_type: 'Training', foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :order, foreign_type: 'Order', foreign_key: 'item_id', inverse_of: :payment_gateway_object belongs_to :payment_gateway_object # some objects may require a reference to another object for remote recovery diff --git a/app/models/payment_schedule.rb b/app/models/payment_schedule.rb index c6b0c7587..43e36596c 100644 --- a/app/models/payment_schedule.rb +++ b/app/models/payment_schedule.rb @@ -11,9 +11,9 @@ class PaymentSchedule < PaymentDocument belongs_to :statistic_profile belongs_to :operator_profile, class_name: 'InvoicingProfile' - has_many :payment_schedule_items - has_many :payment_gateway_objects, as: :item - has_many :payment_schedule_objects + has_many :payment_schedule_items, dependent: :destroy + has_many :payment_gateway_objects, as: :item, dependent: :destroy + has_many :payment_schedule_objects, dependent: :destroy before_create :add_environment after_create :update_reference, :chain_record diff --git a/app/models/payment_schedule_object.rb b/app/models/payment_schedule_object.rb index b5785d16c..9036897b1 100644 --- a/app/models/payment_schedule_object.rb +++ b/app/models/payment_schedule_object.rb @@ -3,11 +3,10 @@ # Links an object bought and a payment schedule used to pay this object class PaymentScheduleObject < Footprintable belongs_to :object, polymorphic: true - belongs_to :reservation, foreign_type: 'Reservation', foreign_key: 'object_id' - belongs_to :subscription, foreign_type: 'Subscription', foreign_key: 'object_id' - belongs_to :wallet_transaction, foreign_type: 'WalletTransaction', foreign_key: 'object_id' - belongs_to :offer_day, foreign_type: 'OfferDay', foreign_key: 'object_id' - belongs_to :statistic_profile_prepaid_pack, foreign_type: 'StatisticProfilePrepaidPack', foreign_key: 'object_id' + belongs_to :reservation, foreign_type: 'Reservation', foreign_key: 'object_id', inverse_of: :payment_schedule_object + belongs_to :subscription, foreign_type: 'Subscription', foreign_key: 'object_id', inverse_of: :payment_schedule_object + belongs_to :statistic_profile_prepaid_pack, foreign_type: 'StatisticProfilePrepaidPack', foreign_key: 'object_id', + inverse_of: :payment_schedule_object belongs_to :payment_schedule after_create :chain_record diff --git a/app/models/projects_space.rb b/app/models/projects_space.rb new file mode 100644 index 000000000..08ec44851 --- /dev/null +++ b/app/models/projects_space.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# ProjectsSpace is the relation table between a Project and a Space +# => spaces used in a project +class ProjectsSpace < ApplicationRecord + belongs_to :space + belongs_to :project +end diff --git a/app/models/setting.rb b/app/models/setting.rb index e61e7e90c..de078dbf8 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -156,7 +156,8 @@ class Setting < ApplicationRecord show_username_in_admin_list store_module store_withdrawal_instructions - store_hidden] } + store_hidden + advanced_accounting] } # WARNING: when adding a new key, you may also want to add it in: # - config/locales/en.yml#settings # - app/frontend/src/javascript/models/setting.ts#SettingName diff --git a/app/models/space.rb b/app/models/space.rb index 934b51754..6dfaacf0b 100644 --- a/app/models/space.rb +++ b/app/models/space.rb @@ -14,9 +14,10 @@ class Space < ApplicationRecord has_many :space_files, as: :viewable, dependent: :destroy accepts_nested_attributes_for :space_files, allow_destroy: true, reject_if: :all_blank - has_and_belongs_to_many :projects, join_table: :projects_spaces + has_many :projects_spaces, dependent: :destroy + has_many :projects, through: :projects_spaces - has_many :spaces_availabilities + has_many :spaces_availabilities, dependent: :destroy has_many :availabilities, through: :spaces_availabilities, dependent: :destroy has_many :reservations, as: :reservable, dependent: :destroy @@ -25,7 +26,10 @@ class Space < ApplicationRecord has_many :prepaid_packs, as: :priceable, dependent: :destroy has_many :credits, as: :creditable, dependent: :destroy - has_one :payment_gateway_object, as: :item + has_one :payment_gateway_object, as: :item, dependent: :destroy + + has_one :advanced_accounting, as: :accountable, dependent: :destroy + accepts_nested_attributes_for :advanced_accounting, allow_destroy: true after_create :create_statistic_subtype after_create :create_space_prices @@ -34,30 +38,29 @@ class Space < ApplicationRecord after_update :update_statistic_subtype, if: :saved_change_to_name? after_destroy :remove_statistic_subtype - def create_statistic_subtype index = StatisticIndex.find_by(es_type_key: 'space') - StatisticSubType.create!({statistic_types: index.statistic_types, key: self.slug, label: self.name}) + StatisticSubType.create!({ statistic_types: index.statistic_types, key: slug, label: name }) end def update_statistic_subtype index = StatisticIndex.find_by(es_type_key: 'space') - subtype = StatisticSubType.joins(statistic_type_sub_types: :statistic_type).find_by(key: self.slug, statistic_types: { statistic_index_id: index.id }) - subtype.label = self.name - subtype.save! + subtype = StatisticSubType.joins(statistic_type_sub_types: :statistic_type) + .find_by(key: slug, statistic_types: { statistic_index_id: index.id }) + subtype.update(label: name) end def remove_statistic_subtype - subtype = StatisticSubType.find_by(key: self.slug) + subtype = StatisticSubType.find_by(key: slug) subtype.destroy! end def create_space_prices - Group.all.each do |group| + Group.find_each do |group| Price.create(priceable: self, group: group, amount: 0) end - Plan.all.includes(:group).each do |plan| + Plan.includes(:group).find_each do |plan| Price.create(group: plan.group, plan: plan, priceable: self, amount: 0) end end diff --git a/app/models/training.rb b/app/models/training.rb index af0a47003..1e1c5017e 100644 --- a/app/models/training.rb +++ b/app/models/training.rb @@ -10,9 +10,10 @@ class Training < ApplicationRecord has_one :training_image, as: :viewable, dependent: :destroy accepts_nested_attributes_for :training_image, allow_destroy: true - has_and_belongs_to_many :machines, join_table: 'trainings_machines' + has_many :trainings_machines, dependent: :destroy + has_many :machines, through: :trainings_machines - has_many :trainings_availabilities + has_many :trainings_availabilities, dependent: :destroy has_many :availabilities, through: :trainings_availabilities, dependent: :destroy has_many :reservations, as: :reservable, dependent: :destroy @@ -26,7 +27,10 @@ class Training < ApplicationRecord has_many :credits, as: :creditable, dependent: :destroy has_many :plans, through: :credits - has_one :payment_gateway_object, as: :item + has_one :payment_gateway_object, as: :item, dependent: :destroy + + has_one :advanced_accounting, as: :accountable, dependent: :destroy + accepts_nested_attributes_for :advanced_accounting, allow_destroy: true after_create :create_statistic_subtype after_create :create_trainings_pricings @@ -40,20 +44,19 @@ class Training < ApplicationRecord end def create_statistic_subtype - index = StatisticIndex.where(es_type_key: 'training') - StatisticSubType.create!(statistic_types: index.first.statistic_types, key: slug, label: name) + index = StatisticIndex.find_by(es_type_key: 'training') + StatisticSubType.create!(statistic_types: index.statistic_types, key: slug, label: name) end def update_statistic_subtype index = StatisticIndex.where(es_type_key: 'training') subtype = StatisticSubType.joins(statistic_type_sub_types: :statistic_type) - .where(key: slug, statistic_types: { statistic_index_id: index.first.id }).first - subtype.label = name - subtype.save! + .find_by(key: slug, statistic_types: { statistic_index_id: index.id }) + subtype.update(label: name) end def remove_statistic_subtype - subtype = StatisticSubType.where(key: slug).first + subtype = StatisticSubType.find_by(key: slug) subtype.destroy! end @@ -64,7 +67,7 @@ class Training < ApplicationRecord private def create_trainings_pricings - Group.all.each do |group| + Group.find_each do |group| TrainingsPricing.create(training: self, group: group, amount: 0) end end diff --git a/app/services/event/create_event_service.rb b/app/services/event/create_event_service.rb new file mode 100644 index 000000000..258cf4ce0 --- /dev/null +++ b/app/services/event/create_event_service.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +# Provides helper methods to create new Events and its recurring occurrences +class Event::CreateEventService + class << self + def create_occurence(event, date) + service = Availabilities::CreateAvailabilitiesService.new + occurrence = Event.new( + recurrence: 'none', + title: title, + description: event.description, + event_image: occurrence_image(event), + event_files: occurrence_files(event), + availability: Availability.new(start_at: occurence_start_date(event, date), + end_at: occurrence_end_date(event, date), + available_type: 'event'), + availability_id: nil, + category_id: event.category_id, + age_range_id: event.age_range_id, + event_themes: event.event_themes, + amount: event.amount, + event_price_categories: occurrence_price_categories(event), + nb_total_places: event.nb_total_places, + recurrence_id: event.id + ) + occurrence.save + service.create_slots(occurrence.availability) + end + + 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) + 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) + end + + def occurrence_image(event) + EventImage.new(attachment: event.event_image.attachment) if event.event_image + end + + def occurrence_files(event) + event.event_files.map do |f| + EventFile.new(attachment: f.attachment) + end + end + + def occurrence_price_categories(event) + event.event_price_categories.map do |epc| + EventPriceCategory.new(price_category_id: epc.price_category_id, amount: epc.amount) + end + end + end +end diff --git a/app/services/event/update_event_service.rb b/app/services/event/update_event_service.rb new file mode 100644 index 000000000..3f1017c4b --- /dev/null +++ b/app/services/event/update_event_service.rb @@ -0,0 +1,141 @@ +# frozen_string_literal: true + +# Provides helper methods to update existing Events and their recurring occurrences +class Event::UpdateEventService + class << self + # update one or more events (if periodic) + def update(event, event_params, mode = 'single') + events = case mode + when 'single' + [event] + when 'next' + Event.includes(:availability, :event_price_categories, :event_files) + .where( + 'availabilities.start_at >= ? AND events.recurrence_id = ?', + event.availability.start_at, + event.recurrence_id + ) + .references(:availabilities, :events) + when 'all' + Event.includes(:availability, :event_price_categories, :event_files) + .where(recurrence_id: event.recurrence_id) + else + [] + end + update_occurrences(event, events, event_params) + end + + private + + def update_occurrences(base_event, occurrences, event_params) + results = { + events: [], + slots: [] + } + original_slots_ids = base_event.availability.slots.map(&:id) + + occurrences.each do |occurrence| + next unless occurrence.id != base_event.id + + e_params = occurrence_params(base_event, occurrence, event_params) + begin + results[:events].push status: !!occurrence.update(e_params.permit!), event: occurrence # rubocop:disable Style/DoubleNegation + rescue StandardError => e + results[:events].push status: false, event: occurrence, error: e.try(:record).try(:class).try(:name), message: e.message + end + results[:slots].concat(update_slots(occurrence.availability_id, original_slots_ids)) + end + + begin + event_params[:availability_attributes][:id] = base_event.availability_id + results[:events].push status: !!base_event.update(event_params), event: base_event # rubocop:disable Style/DoubleNegation + rescue StandardError => e + results[:events].push status: false, event: base_event, error: e.try(:record).try(:class).try(:name), message: e.message + end + results[:slots].concat(update_slots(base_event.availability_id, original_slots_ids)) + results + end + + def update_slots(availability_id, original_slots_ids) + results = [] + avail = Availability.find(availability_id) + Slot.where(id: original_slots_ids).each do |slot| + results.push( + status: !!slot.update(availability_id: availability_id, start_at: avail.start_at, end_at: avail.end_at), # rubocop:disable Style/DoubleNegation + slot: slot + ) + rescue StandardError => e + results.push status: false, slot: s, error: e.try(:record).try(:class).try(:name), message: e.message + end + results + end + + def occurrence_params(base_event, occurrence, event_params) + start_at = event_params['availability_attributes']['start_at'] + end_at = event_params['availability_attributes']['end_at'] + e_params = event_params.merge( + availability_id: occurrence.availability_id, + availability_attributes: { + id: occurrence.availability_id, + start_at: occurrence.availability.start_at.change(hour: start_at.hour, min: start_at.min), + end_at: occurrence.availability.end_at.change(hour: end_at.hour, min: end_at.min), + available_type: occurrence.availability.available_type + } + ) + epc_attributes = price_categories_attributes(base_event, occurrence, event_params) + unless epc_attributes.empty? + e_params = e_params.merge( + event_price_categories_attributes: epc_attributes + ) + end + + ef_attributes = file_attributes(base_event, occurrence, event_params) + e_params.merge( + event_files_attributes: ef_attributes + ) + end + + def price_categories_attributes(base_event, occurrence, event_params) + epc_attributes = [] + event_params['event_price_categories_attributes']&.each do |epca| + epc = occurrence.event_price_categories.find_by(price_category_id: epca['price_category_id']) + if epc + epc_attributes.push( + id: epc.id, + price_category_id: epc.price_category_id, + amount: epca['amount'], + _destroy: epca['_destroy'] + ) + elsif epca['id'].present? + event_price = base_event.event_price_categories.find(epca['id']) + epc_attributes.push( + price_category_id: epca['price_category_id'], + amount: event_price.amount, + _destroy: '' + ) + end + end + epc_attributes + end + + def file_attributes(base_event, occurrence, event_params) + ef_attributes = [] + event_params['event_files_attributes']&.each do |efa| + if efa['id'].present? + event_file = base_event.event_files.find(efa['id']) + ef = occurrence.event_files.find_by(attachment: event_file.attachment.file.filename) + if ef + ef_attributes.push( + id: ef.id, + attachment: efa['attachment'], + _destroy: efa['_destroy'] + ) + end + else + ef_attributes.push(efa) + end + end + ef_attributes + end + end +end diff --git a/app/services/event_service.rb b/app/services/event_service.rb index f6b68dbdf..dcb7ea0af 100644 --- a/app/services/event_service.rb +++ b/app/services/event_service.rb @@ -75,140 +75,5 @@ class EventService end results end - - # update one or more events (if periodic) - def update(event, event_params, mode = 'single') - events = case mode - when 'single' - [event] - when 'next' - Event.includes(:availability, :event_price_categories, :event_files) - .where( - 'availabilities.start_at >= ? AND events.recurrence_id = ?', - event.availability.start_at, - event.recurrence_id - ) - .references(:availabilities, :events) - when 'all' - Event.includes(:availability, :event_price_categories, :event_files) - .where(recurrence_id: event.recurrence_id) - else - [] - end - update_occurrences(event, events, event_params) - end - - private - - def update_occurrences(base_event, occurrences, event_params) - results = { - events: [], - slots: [] - } - original_slots_ids = base_event.availability.slots.map(&:id) - - occurrences.each do |occurrence| - next unless occurrence.id != base_event.id - - e_params = occurrence_params(base_event, occurrence, event_params) - begin - results[:events].push status: !!occurrence.update(e_params.permit!), event: occurrence # rubocop:disable Style/DoubleNegation - rescue StandardError => e - results[:events].push status: false, event: occurrence, error: e.try(:record).try(:class).try(:name), message: e.message - end - results[:slots].concat(update_slots(occurrence.availability_id, original_slots_ids)) - end - - begin - event_params[:availability_attributes][:id] = base_event.availability_id - results[:events].push status: !!base_event.update(event_params), event: base_event # rubocop:disable Style/DoubleNegation - rescue StandardError => e - results[:events].push status: false, event: base_event, error: e.try(:record).try(:class).try(:name), message: e.message - end - results[:slots].concat(update_slots(base_event.availability_id, original_slots_ids)) - results - end - - def update_slots(availability_id, original_slots_ids) - results = [] - avail = Availability.find(availability_id) - Slot.where(id: original_slots_ids).each do |slot| - results.push( - status: !!slot.update(availability_id: availability_id, start_at: avail.start_at, end_at: avail.end_at), # rubocop:disable Style/DoubleNegation - slot: slot - ) - rescue StandardError => e - results.push status: false, slot: s, error: e.try(:record).try(:class).try(:name), message: e.message - end - results - end - - def occurrence_params(base_event, occurrence, event_params) - start_at = event_params['availability_attributes']['start_at'] - end_at = event_params['availability_attributes']['end_at'] - e_params = event_params.merge( - availability_id: occurrence.availability_id, - availability_attributes: { - id: occurrence.availability_id, - start_at: occurrence.availability.start_at.change(hour: start_at.hour, min: start_at.min), - end_at: occurrence.availability.end_at.change(hour: end_at.hour, min: end_at.min), - available_type: occurrence.availability.available_type - } - ) - epc_attributes = price_categories_attributes(base_event, occurrence, event_params) - unless epc_attributes.empty? - e_params = e_params.merge( - event_price_categories_attributes: epc_attributes - ) - end - - ef_attributes = file_attributes(base_event, occurrence, event_params) - e_params.merge( - event_files_attributes: ef_attributes - ) - end - - def price_categories_attributes(base_event, occurrence, event_params) - epc_attributes = [] - event_params['event_price_categories_attributes']&.each do |epca| - epc = occurrence.event_price_categories.find_by(price_category_id: epca['price_category_id']) - if epc - epc_attributes.push( - id: epc.id, - price_category_id: epc.price_category_id, - amount: epca['amount'], - _destroy: epca['_destroy'] - ) - elsif epca['id'].present? - event_price = base_event.event_price_categories.find(epca['id']) - epc_attributes.push( - price_category_id: epca['price_category_id'], - amount: event_price.amount, - _destroy: '' - ) - end - end - epc_attributes - end - - def file_attributes(base_event, occurrence, event_params) - ef_attributes = [] - event_params['event_files_attributes']&.each do |efa| - if efa['id'].present? - event_file = base_event.event_files.find(efa['id']) - ef = occurrence.event_files.find_by(attachment: event_file.attachment.file.filename) - if ef - ef_attributes.push( - id: ef.id, - attachment: efa['attachment'], - _destroy: efa['_destroy'] - ) - end - else - ef_attributes.push(efa) - end - end - ef_attributes - end end end diff --git a/app/views/api/advanced_accounting/_advanced_accounting.json.jbuilder b/app/views/api/advanced_accounting/_advanced_accounting.json.jbuilder new file mode 100644 index 000000000..7d150eabd --- /dev/null +++ b/app/views/api/advanced_accounting/_advanced_accounting.json.jbuilder @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +json.extract! advanced_accounting, :id, :code, :analytical_section diff --git a/app/views/api/events/_event.json.jbuilder b/app/views/api/events/_event.json.jbuilder index a3f24666e..aa54add86 100644 --- a/app/views/api/events/_event.json.jbuilder +++ b/app/views/api/events/_event.json.jbuilder @@ -58,3 +58,8 @@ end json.nb_total_places event.nb_total_places json.nb_free_places event.nb_free_places || event.nb_total_places +if event.advanced_accounting + json.advanced_accounting_attributes do + json.partial! 'api/advanced_accounting/advanced_accounting', advanced_accounting: event.advanced_accounting + end +end diff --git a/app/views/api/machines/_machine.json.jbuilder b/app/views/api/machines/_machine.json.jbuilder index 22e41d7ee..df26c4b9f 100644 --- a/app/views/api/machines/_machine.json.jbuilder +++ b/app/views/api/machines/_machine.json.jbuilder @@ -9,3 +9,9 @@ if machine.machine_image json.attachment_url machine.machine_image.attachment.url end end + +if machine.advanced_accounting + json.advanced_accounting_attributes do + json.partial! 'api/advanced_accounting/advanced_accounting', advanced_accounting: machine.advanced_accounting + end +end diff --git a/app/views/api/spaces/_space.json.jbuilder b/app/views/api/spaces/_space.json.jbuilder index 632a0fd60..6daf5c976 100644 --- a/app/views/api/spaces/_space.json.jbuilder +++ b/app/views/api/spaces/_space.json.jbuilder @@ -8,3 +8,9 @@ if space.space_image json.attachment_url space.space_image.attachment.url end end + +if space.advanced_accounting + json.advanced_accounting_attributes do + json.partial! 'api/advanced_accounting/advanced_accounting', advanced_accounting: space.advanced_accounting + end +end diff --git a/app/views/api/trainings/_training.json.jbuilder b/app/views/api/trainings/_training.json.jbuilder index 4c55b6741..443404389 100644 --- a/app/views/api/trainings/_training.json.jbuilder +++ b/app/views/api/trainings/_training.json.jbuilder @@ -8,3 +8,9 @@ if training.training_image json.attachment_url training.training_image.attachment.url end end + +if training.advanced_accounting + json.advanced_accounting_attributes do + json.partial! 'api/advanced_accounting/advanced_accounting', advanced_accounting: training.advanced_accounting + end +end diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 4733610b8..39866670e 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -87,6 +87,10 @@ en: edit_all: "All events" date_wont_change: "Warning: you have changed the event date. This modification won't be propagated to other occurrences of the periodic event." confirm: "Update the {MODE, select, single{event} other{events}}" + advanced_accounting_form: + title: "Advanced accounting parameters" + code: "Accounting code" + analytical_section: "Analytical section" #add a new machine machines_new: declare_a_new_machine: "Declare a new machine" diff --git a/config/locales/en.yml b/config/locales/en.yml index d6866be60..5b976887b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -622,3 +622,4 @@ en: store_module: "Store module" store_withdrawal_instructions: "Withdrawal instructions" store_hidden: "Store hidden to the public" + advanced_accounting: "Advanced accounting" diff --git a/db/migrate/20221110120338_create_advanced_accountings.rb b/db/migrate/20221110120338_create_advanced_accountings.rb new file mode 100644 index 000000000..119405815 --- /dev/null +++ b/db/migrate/20221110120338_create_advanced_accountings.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# Advanced accouting parameters are stored in a dedicated table, +# with a polymorphic relation per object +class CreateAdvancedAccountings < ActiveRecord::Migration[5.2] + def change + create_table :advanced_accountings do |t| + t.string :code + t.string :analytical_section + t.references :accountable, polymorphic: true, index: { name: 'index_advanced_accountings_on_accountable' } + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index effaba6fc..261db0394 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -19,8 +19,8 @@ ActiveRecord::Schema.define(version: 2022_11_22_123605) do enable_extension "unaccent" create_table "abuses", id: :serial, force: :cascade do |t| - t.string "signaled_type" t.integer "signaled_id" + t.string "signaled_type" t.string "first_name" t.string "last_name" t.string "email" @@ -49,12 +49,22 @@ ActiveRecord::Schema.define(version: 2022_11_22_123605) do t.string "locality" t.string "country" t.string "postal_code" - t.string "placeable_type" t.integer "placeable_id" + t.string "placeable_type" t.datetime "created_at" t.datetime "updated_at" end + create_table "advanced_accountings", force: :cascade do |t| + t.string "code" + t.string "analytical_section" + t.string "accountable_type" + t.bigint "accountable_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["accountable_type", "accountable_id"], name: "index_advanced_accountings_on_accountable" + end + create_table "age_ranges", id: :serial, force: :cascade do |t| t.string "name" t.datetime "created_at", null: false @@ -64,8 +74,8 @@ ActiveRecord::Schema.define(version: 2022_11_22_123605) do end create_table "assets", id: :serial, force: :cascade do |t| - t.string "viewable_type" t.integer "viewable_id" + t.string "viewable_type" t.string "attachment" t.string "type" t.datetime "created_at" @@ -147,8 +157,8 @@ ActiveRecord::Schema.define(version: 2022_11_22_123605) do end create_table "credits", id: :serial, force: :cascade do |t| - t.string "creditable_type" t.integer "creditable_id" + t.string "creditable_type" t.integer "plan_id" t.integer "hours" t.datetime "created_at" @@ -377,15 +387,15 @@ ActiveRecord::Schema.define(version: 2022_11_22_123605) do create_table "notifications", id: :serial, force: :cascade do |t| t.integer "receiver_id" - t.string "attached_object_type" t.integer "attached_object_id" + t.string "attached_object_type" t.integer "notification_type_id" t.boolean "is_read", default: false t.datetime "created_at" t.datetime "updated_at" t.string "receiver_type" t.boolean "is_send", default: false - t.jsonb "meta_data", default: "{}" + t.jsonb "meta_data", default: {} t.index ["notification_type_id"], name: "index_notifications_on_notification_type_id" t.index ["receiver_id"], name: "index_notifications_on_receiver_id" end @@ -625,8 +635,8 @@ ActiveRecord::Schema.define(version: 2022_11_22_123605) do create_table "prices", id: :serial, force: :cascade do |t| t.integer "group_id" t.integer "plan_id" - t.string "priceable_type" t.integer "priceable_id" + t.string "priceable_type" t.integer "amount" t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -826,8 +836,8 @@ ActiveRecord::Schema.define(version: 2022_11_22_123605) do t.text "message" t.datetime "created_at" t.datetime "updated_at" - t.string "reservable_type" t.integer "reservable_id" + t.string "reservable_type" t.integer "nb_reserve_places" t.integer "statistic_profile_id" t.index ["reservable_type", "reservable_id"], name: "index_reservations_on_reservable_type_and_reservable_id" @@ -836,8 +846,8 @@ ActiveRecord::Schema.define(version: 2022_11_22_123605) do create_table "roles", id: :serial, force: :cascade do |t| t.string "name" - t.string "resource_type" t.integer "resource_id" + t.string "resource_type" t.datetime "created_at" t.datetime "updated_at" t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id" @@ -1119,8 +1129,8 @@ ActiveRecord::Schema.define(version: 2022_11_22_123605) do t.boolean "is_allow_newsletter" t.inet "current_sign_in_ip" t.inet "last_sign_in_ip" - t.datetime "validated_at" t.string "mapped_from_sso" + t.datetime "validated_at" t.index ["auth_token"], name: "index_users_on_auth_token" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true diff --git a/db/seeds.rb b/db/seeds.rb index 0fa2660cd..1b26cbdca 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -993,6 +993,8 @@ Setting.set('store_module', false) unless Setting.find_by(name: 'store_module'). Setting.set('store_hidden', true) unless Setting.find_by(name: 'store_hidden').try(:value) +Setting.set('advanced_accounting', false) unless Setting.find_by(name: 'advanced_accounting').try(:value) + if StatisticCustomAggregation.count.zero? # available reservations hours for machines machine_hours = StatisticType.find_by(key: 'hour', statistic_index_id: 2)