mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-30 19:52:20 +01:00
(feat) advanced accounting parameters
for: machines, spaces, trainings, events
This commit is contained in:
parent
3d796549f2
commit
7868f31a58
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<TFieldValues> {
|
||||
register: UseFormRegister<TFieldValues>,
|
||||
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 = <TFieldValues extends FieldValues>({ register, onError }: AdvancedAccountingFormProps<TFieldValues>) => {
|
||||
const [isEnabled, setIsEnabled] = useState<boolean>(false);
|
||||
|
||||
const { t } = useTranslation('admin');
|
||||
|
||||
useEffect(() => {
|
||||
SettingAPI.get('advanced_accounting').then(res => setIsEnabled(res.value === 'true')).catch(onError);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="advanced-accounting-form">
|
||||
{isEnabled && <div>
|
||||
<h4>{t('app.admin.advanced_accounting_form.title')}</h4>
|
||||
<FormInput register={register}
|
||||
id="advanced_accounting_attributes.code"
|
||||
label={t('app.admin.advanced_accounting_form.code')} />
|
||||
<FormInput register={register}
|
||||
id="advanced_accounting_attributes.analytical_section"
|
||||
label={t('app.admin.advanced_accounting_form.analytical_section')} />
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
};
|
@ -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<EventFormProps> = ({ action, event, onError, on
|
||||
id="event_files_attributes"
|
||||
className="event-files" />
|
||||
</div>
|
||||
<AdvancedAccountingForm register={register} onError={onError} />
|
||||
<FabButton type="submit" className="is-info submit-btn">
|
||||
{t('app.admin.event_form.ACTION_event', { ACTION: action })}
|
||||
</FabButton>
|
||||
|
@ -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<MachineFormProps> = ({ action, machine, onErr
|
||||
id="disabled"
|
||||
label={t('app.admin.machine_form.disable_machine')}
|
||||
tooltip={t('app.admin.machine_form.disabled_help')} />
|
||||
<AdvancedAccountingForm register={register} onError={onError} />
|
||||
<FabButton type="submit" className="is-info submit-btn">
|
||||
{t('app.admin.machine_form.ACTION_machine', { ACTION: action })}
|
||||
</FabButton>
|
||||
|
@ -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<SpaceFormProps> = ({ action, space, onError, on
|
||||
id="disabled"
|
||||
label={t('app.admin.space_form.disable_space')}
|
||||
tooltip={t('app.admin.space_form.disabled_help')} />
|
||||
<AdvancedAccountingForm register={register} onError={onError} />
|
||||
<FabButton type="submit" className="is-info submit-btn">
|
||||
{t('app.admin.space_form.ACTION_space', { ACTION: action })}
|
||||
</FabButton>
|
||||
|
@ -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<TrainingFormProps> = ({ action, training, on
|
||||
id="disabled"
|
||||
label={t('app.admin.training_form.disable_training')}
|
||||
tooltip={t('app.admin.training_form.disabled_help')} />
|
||||
<AdvancedAccountingForm register={register} onError={onError} />
|
||||
<FabButton type="submit" className="is-info submit-btn">
|
||||
{t('app.admin.training_form.ACTION_training', { ACTION: action })}
|
||||
</FabButton>
|
||||
|
@ -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));
|
||||
|
@ -0,0 +1,5 @@
|
||||
export interface AdvancedAccounting {
|
||||
id?: number,
|
||||
code?: string,
|
||||
analytical_section?: string
|
||||
}
|
@ -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 {
|
||||
|
@ -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<FileType>,
|
||||
trainings?: Array<{
|
||||
id: number,
|
||||
name: string,
|
||||
@ -31,5 +29,6 @@ export interface Machine {
|
||||
id: number,
|
||||
name: string,
|
||||
slug: string,
|
||||
}>
|
||||
}>,
|
||||
advanced_accounting_attributes?: AdvancedAccounting
|
||||
}
|
||||
|
@ -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 = [
|
||||
|
@ -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<FileType>
|
||||
space_file_attributes?: Array<FileType>,
|
||||
advanced_accounting_attributes?: AdvancedAccounting
|
||||
}
|
||||
|
@ -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 {
|
||||
|
10
app/models/advanced_accounting.rb
Normal file
10
app/models/advanced_accounting.rb
Normal file
@ -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
|
@ -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
|
||||
|
8
app/models/events_event_theme.rb
Normal file
8
app/models/events_event_theme.rb
Normal file
@ -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
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
8
app/models/projects_space.rb
Normal file
8
app/models/projects_space.rb
Normal file
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
64
app/services/event/create_event_service.rb
Normal file
64
app/services/event/create_event_service.rb
Normal file
@ -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
|
141
app/services/event/update_event_service.rb
Normal file
141
app/services/event/update_event_service.rb
Normal file
@ -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
|
@ -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
|
||||
|
@ -0,0 +1,3 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.extract! advanced_accounting, :id, :code, :analytical_section
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
15
db/migrate/20221110120338_create_advanced_accountings.rb
Normal file
15
db/migrate/20221110120338_create_advanced_accountings.rb
Normal file
@ -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
|
30
db/schema.rb
30
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
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user