mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-30 19:52:20 +01:00
transactional bulk update + better error handling while configuring the payment gateway
This commit is contained in:
parent
ef69cab179
commit
a416f8c7ae
@ -12,7 +12,7 @@ class API::SettingsController < API::ApiController
|
|||||||
authorize Setting
|
authorize Setting
|
||||||
@setting = Setting.find_or_initialize_by(name: params[:name])
|
@setting = Setting.find_or_initialize_by(name: params[:name])
|
||||||
render status: :not_modified and return if setting_params[:value] == @setting.value
|
render status: :not_modified and return if setting_params[:value] == @setting.value
|
||||||
render status: :locked, json: { error: 'locked setting' } and return unless SettingService.before_update(@setting)
|
render status: :locked, json: { error: I18n.t('settings.locked_setting') } and return unless SettingService.before_update(@setting)
|
||||||
|
|
||||||
if @setting.save && @setting.history_values.create(value: setting_params[:value], invoicing_profile: current_user.invoicing_profile)
|
if @setting.save && @setting.history_values.create(value: setting_params[:value], invoicing_profile: current_user.invoicing_profile)
|
||||||
SettingService.after_update(@setting)
|
SettingService.after_update(@setting)
|
||||||
@ -26,18 +26,21 @@ class API::SettingsController < API::ApiController
|
|||||||
authorize Setting
|
authorize Setting
|
||||||
|
|
||||||
@settings = []
|
@settings = []
|
||||||
params[:settings].each do |setting|
|
may_transaction(params[:transactional]) do
|
||||||
next if !setting[:name] || !setting[:value]
|
params[:settings].each do |setting|
|
||||||
|
next if !setting[:name] || !setting[:value]
|
||||||
|
|
||||||
db_setting = Setting.find_or_initialize_by(name: setting[:name])
|
db_setting = Setting.find_or_initialize_by(name: setting[:name])
|
||||||
next unless SettingService.before_update(db_setting)
|
if !SettingService.before_update(db_setting)
|
||||||
|
db_setting.errors[:-] << I18n.t("settings.#{setting[:name]}") + ': ' + I18n.t('settings.locked_setting')
|
||||||
|
elsif db_setting.save
|
||||||
|
db_setting.history_values.create(value: setting[:value], invoicing_profile: current_user.invoicing_profile)
|
||||||
|
SettingService.after_update(db_setting)
|
||||||
|
end
|
||||||
|
|
||||||
if db_setting.save
|
@settings.push db_setting
|
||||||
db_setting.history_values.create(value: setting[:value], invoicing_profile: current_user.invoicing_profile)
|
may_rollback(params[:transactional]) if db_setting.errors.keys.count.positive?
|
||||||
SettingService.after_update(db_setting)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@settings.push db_setting
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -79,4 +82,20 @@ class API::SettingsController < API::ApiController
|
|||||||
def names_as_string_to_array
|
def names_as_string_to_array
|
||||||
params[:names][1..-2].split(',').map(&:strip).map { |param| param[1..-2] }.map(&:strip)
|
params[:names][1..-2].split(',').map(&:strip).map { |param| param[1..-2] }.map(&:strip)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# run the given block in a transaction if `should` is true. Just run it normally otherwise
|
||||||
|
def may_transaction(should)
|
||||||
|
if should == 'true'
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
else
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# rollback the current DB transaction if `should` is true
|
||||||
|
def may_rollback(should)
|
||||||
|
raise ActiveRecord::Rollback if should == 'true'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -23,8 +23,8 @@ export default class SettingAPI {
|
|||||||
return res?.data?.setting;
|
return res?.data?.setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
async bulkUpdate (settings: Map<SettingName, any>): Promise<Map<SettingName, SettingBulkResult>> {
|
async bulkUpdate (settings: Map<SettingName, any>, transactional: boolean = false): Promise<Map<SettingName, SettingBulkResult>> {
|
||||||
const res: AxiosResponse = await apiClient.patch('/api/settings/bulk_update', { settings: SettingAPI.toObjectArray(settings) });
|
const res: AxiosResponse = await apiClient.patch(`/api/settings/bulk_update?transactional=${transactional}`, { settings: SettingAPI.toObjectArray(settings) });
|
||||||
return SettingAPI.toBulkMap(res?.data?.settings);
|
return SettingAPI.toBulkMap(res?.data?.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,6 +67,9 @@ export default class SettingAPI {
|
|||||||
if ('value' in item) {
|
if ('value' in item) {
|
||||||
itemData.value = item.value;
|
itemData.value = item.value;
|
||||||
}
|
}
|
||||||
|
if ('localized' in item) {
|
||||||
|
itemData.localized = item.localized;
|
||||||
|
}
|
||||||
|
|
||||||
map.set(item.name as SettingName, itemData)
|
map.set(item.name as SettingName, itemData)
|
||||||
});
|
});
|
||||||
|
@ -23,7 +23,7 @@ interface SelectGatewayModalModalProps {
|
|||||||
isOpen: boolean,
|
isOpen: boolean,
|
||||||
toggleModal: () => void,
|
toggleModal: () => void,
|
||||||
currentUser: User,
|
currentUser: User,
|
||||||
onError: (errors: Map<SettingName, SettingBulkResult>|any) => void,
|
onError: (errors: string) => void,
|
||||||
onSuccess: (results: Map<SettingName, SettingBulkResult>) => void,
|
onSuccess: (results: Map<SettingName, SettingBulkResult>) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,10 +102,12 @@ const SelectGatewayModal: React.FC<SelectGatewayModalModalProps> = ({ isOpen, to
|
|||||||
settings.set(SettingName.PaymentGateway, selectedGateway);
|
settings.set(SettingName.PaymentGateway, selectedGateway);
|
||||||
|
|
||||||
const api = new SettingAPI();
|
const api = new SettingAPI();
|
||||||
api.bulkUpdate(settings).then(result => {
|
api.bulkUpdate(settings, true).then(result => {
|
||||||
if (Array.from(result.values()).filter(item => !item.status).length > 0) {
|
const errorResults = Array.from(result.values()).filter(item => !item.status);
|
||||||
onError(result);
|
if (errorResults.length > 0) {
|
||||||
|
onError(errorResults.map(item => item.error[0]).join(' '));
|
||||||
} else {
|
} else {
|
||||||
|
// we call the success callback only in case of full success (transactional bulk update)
|
||||||
onSuccess(result);
|
onSuccess(result);
|
||||||
}
|
}
|
||||||
}, reason => {
|
}, reason => {
|
||||||
|
@ -720,9 +720,8 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
|||||||
/**
|
/**
|
||||||
* Callback triggered after the gateway failed to be configured
|
* Callback triggered after the gateway failed to be configured
|
||||||
*/
|
*/
|
||||||
$scope.onGatewayModalError = function (errors) {
|
$scope.onGatewayModalError = function (message) {
|
||||||
growl.error(_t('app.admin.invoices.payment.gateway_configuration_error'));
|
growl.error(_t('app.admin.invoices.payment.gateway_configuration_error') + message);
|
||||||
console.error(errors);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +24,6 @@ export enum SettingName {
|
|||||||
InvoiceLegals = 'invoice_legals',
|
InvoiceLegals = 'invoice_legals',
|
||||||
BookingWindowStart = 'booking_window_start',
|
BookingWindowStart = 'booking_window_start',
|
||||||
BookingWindowEnd = 'booking_window_end',
|
BookingWindowEnd = 'booking_window_end',
|
||||||
BookingSlotDuration = 'booking_slot_duration',
|
|
||||||
BookingMoveEnable = 'booking_move_enable',
|
BookingMoveEnable = 'booking_move_enable',
|
||||||
BookingMoveDelay = 'booking_move_delay',
|
BookingMoveDelay = 'booking_move_delay',
|
||||||
BookingCancelEnable = 'booking_cancel_enable',
|
BookingCancelEnable = 'booking_cancel_enable',
|
||||||
@ -113,6 +112,7 @@ export enum SettingName {
|
|||||||
|
|
||||||
export interface Setting {
|
export interface Setting {
|
||||||
name: SettingName,
|
name: SettingName,
|
||||||
|
localized?: string,
|
||||||
value: string,
|
value: string,
|
||||||
last_update?: Date,
|
last_update?: Date,
|
||||||
history?: Array<HistoryValue>
|
history?: Array<HistoryValue>
|
||||||
@ -127,5 +127,6 @@ export interface SettingError {
|
|||||||
export interface SettingBulkResult {
|
export interface SettingBulkResult {
|
||||||
status: boolean,
|
status: boolean,
|
||||||
value?: any,
|
value?: any,
|
||||||
error?: string
|
error?: string,
|
||||||
|
localized?: string,
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
class Setting < ApplicationRecord
|
class Setting < ApplicationRecord
|
||||||
has_many :history_values
|
has_many :history_values
|
||||||
# The following list contains all the settings that can be customized from the Fab-manager's UI.
|
# The following list contains all the settings that can be customized from the Fab-manager's UI.
|
||||||
# A few of them that are system settings, that should not be updated manually (uuid, origin).
|
# A few of them that are system settings, that should not be updated manually (uuid, origin...).
|
||||||
validates :name, inclusion:
|
validates :name, inclusion:
|
||||||
{ in: %w[about_title
|
{ in: %w[about_title
|
||||||
about_body
|
about_body
|
||||||
@ -32,7 +32,6 @@ class Setting < ApplicationRecord
|
|||||||
invoice_legals
|
invoice_legals
|
||||||
booking_window_start
|
booking_window_start
|
||||||
booking_window_end
|
booking_window_end
|
||||||
booking_slot_duration
|
|
||||||
booking_move_enable
|
booking_move_enable
|
||||||
booking_move_delay
|
booking_move_delay
|
||||||
booking_cancel_enable
|
booking_cancel_enable
|
||||||
|
@ -34,7 +34,7 @@ class SettingPolicy < ApplicationPolicy
|
|||||||
def self.public_whitelist
|
def self.public_whitelist
|
||||||
%w[about_title about_body about_contacts privacy_body privacy_dpo twitter_name home_blogpost machine_explications_alert
|
%w[about_title about_body about_contacts privacy_body privacy_dpo twitter_name home_blogpost machine_explications_alert
|
||||||
training_explications_alert training_information_message subscription_explications_alert booking_window_start
|
training_explications_alert training_information_message subscription_explications_alert booking_window_start
|
||||||
booking_window_end booking_slot_duration booking_move_enable booking_move_delay booking_cancel_enable booking_cancel_delay
|
booking_window_end booking_move_enable booking_move_delay booking_cancel_enable booking_cancel_delay
|
||||||
fablab_name name_genre event_explications_alert space_explications_alert link_name home_content phone_required
|
fablab_name name_genre event_explications_alert space_explications_alert link_name home_content phone_required
|
||||||
tracking_id book_overlapping_slots slot_duration events_in_calendar spaces_module plans_module invoicing_module
|
tracking_id book_overlapping_slots slot_duration events_in_calendar spaces_module plans_module invoicing_module
|
||||||
recaptcha_site_key feature_tour_display disqus_shortname allowed_cad_extensions openlab_app_id openlab_default
|
recaptcha_site_key feature_tour_display disqus_shortname allowed_cad_extensions openlab_app_id openlab_default
|
||||||
|
@ -1 +1,4 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
json.extract! setting, :name, :value, :last_update
|
json.extract! setting, :name, :value, :last_update
|
||||||
|
json.localized I18n.t("settings.#{setting[:name]}")
|
||||||
|
@ -650,7 +650,7 @@ en:
|
|||||||
currency_info_html: "Please specify below the currency used for online payment. You should provide a three-letter ISO code, from the list of <a href='https://stripe.com/docs/currencies' target='_blank'>Stripe supported currencies</a>."
|
currency_info_html: "Please specify below the currency used for online payment. You should provide a three-letter ISO code, from the list of <a href='https://stripe.com/docs/currencies' target='_blank'>Stripe supported currencies</a>."
|
||||||
currency_alert_html: "<strong>Warning</strong>: the currency cannot be changed after the first online payment was made. Please define this setting carefully before opening Fab-manager to your members."
|
currency_alert_html: "<strong>Warning</strong>: the currency cannot be changed after the first online payment was made. Please define this setting carefully before opening Fab-manager to your members."
|
||||||
stripe_currency: "Stripe currency"
|
stripe_currency: "Stripe currency"
|
||||||
gateway_configuration_error: "An error occurred while configuring the payment gateway."
|
gateway_configuration_error: "An error occurred while configuring the payment gateway: "
|
||||||
payzen:
|
payzen:
|
||||||
payzen_keys: "PayZen keys"
|
payzen_keys: "PayZen keys"
|
||||||
payzen_username: "Username"
|
payzen_username: "Username"
|
||||||
@ -673,6 +673,7 @@ en:
|
|||||||
stripe: "Stripe"
|
stripe: "Stripe"
|
||||||
payzen: "PayZen"
|
payzen: "PayZen"
|
||||||
confirm_button: "Validate the gateway"
|
confirm_button: "Validate the gateway"
|
||||||
|
successfully_updated: " successfully updated"
|
||||||
payment_schedules:
|
payment_schedules:
|
||||||
filter_schedules: "Filter schedules"
|
filter_schedules: "Filter schedules"
|
||||||
no_payment_schedules: "No payment schedules to display"
|
no_payment_schedules: "No payment schedules to display"
|
||||||
|
@ -650,7 +650,7 @@ fr:
|
|||||||
currency_info_html: "Veuillez indiquer la devise à utiliser lors des paiements en ligne. Vous devez fournir un code ISO à trois lettres, issu de la liste des <a href='https://stripe.com/docs/currencies' target='_blank'>devises supportées par Stripe</a>."
|
currency_info_html: "Veuillez indiquer la devise à utiliser lors des paiements en ligne. Vous devez fournir un code ISO à trois lettres, issu de la liste des <a href='https://stripe.com/docs/currencies' target='_blank'>devises supportées par Stripe</a>."
|
||||||
currency_alert_html: "<strong>Attention</strong> : la devise ne peut pas être modifiée après que le premier paiement en ligne ait été effectué. Veuillez définir attentivement ce paramètre avant d'ouvrir Fab-manager à vos membres."
|
currency_alert_html: "<strong>Attention</strong> : la devise ne peut pas être modifiée après que le premier paiement en ligne ait été effectué. Veuillez définir attentivement ce paramètre avant d'ouvrir Fab-manager à vos membres."
|
||||||
stripe_currency: "Devise Stripe"
|
stripe_currency: "Devise Stripe"
|
||||||
gateway_configuration_error: "Une erreur est survenue lors de la configuration de la passerelle de paiement."
|
gateway_configuration_error: "Une erreur est survenue lors de la configuration de la passerelle de paiement : "
|
||||||
payzen:
|
payzen:
|
||||||
payzen_keys: "Clefs PayZen"
|
payzen_keys: "Clefs PayZen"
|
||||||
payzen_username: "Utilisateur"
|
payzen_username: "Utilisateur"
|
||||||
|
@ -414,3 +414,114 @@ en:
|
|||||||
group:
|
group:
|
||||||
#name of the user's group for administrators
|
#name of the user's group for administrators
|
||||||
admins: 'Administrators'
|
admins: 'Administrators'
|
||||||
|
settings:
|
||||||
|
locked_setting: "the setting is locked."
|
||||||
|
about_title: "\"About\" page title"
|
||||||
|
about_body: "\"About\" page content"
|
||||||
|
about_contacts: "\"About\" page contacts"
|
||||||
|
privacy_draft: "Privacy policy draft"
|
||||||
|
privacy_body: "Privacy policy"
|
||||||
|
privacy_dpo: "Data protection officer address"
|
||||||
|
twitter_name: "Twitter feed name"
|
||||||
|
home_blogpost: "Homepage's brief"
|
||||||
|
machine_explications_alert: "Explanation message on the machine reservation page"
|
||||||
|
training_explications_alert: "Explanation message on the training reservation page"
|
||||||
|
training_information_message: "Information message on the machine reservation page"
|
||||||
|
subscription_explications_alert: "Explanation message on the subscription page"
|
||||||
|
invoice_logo: "Invoices' logo"
|
||||||
|
invoice_reference: "Invoice's reference"
|
||||||
|
invoice_code-active: "Activation of the invoices' code"
|
||||||
|
invoice_code-value: "Invoices' code"
|
||||||
|
invoice_order-nb: "Invoice's order number"
|
||||||
|
invoice_VAT-active: "Activation of the VAT"
|
||||||
|
invoice_VAT-rate: "VAT rate"
|
||||||
|
invoice_text: "Invoices' text"
|
||||||
|
invoice_legals: "Invoices' legal information"
|
||||||
|
booking_window_start: "Opening time"
|
||||||
|
booking_window_end: "Closing time"
|
||||||
|
booking_move_enable: "Activation of reservations moving"
|
||||||
|
booking_move_delay: "Preventive delay before any reservation move"
|
||||||
|
booking_cancel_enable: "Activation of reservations cancelling"
|
||||||
|
booking_cancel_delay: "Preventive delay before any reservation cancellation"
|
||||||
|
main_color: "Main colour"
|
||||||
|
secondary_color: "Secondary colour"
|
||||||
|
fablab_name: "Fablab's name"
|
||||||
|
name_genre: "Title concordance"
|
||||||
|
reminder_enable: "Activation of reservations reminding"
|
||||||
|
reminder_delay: "Delay before sending the reminder"
|
||||||
|
event_explications_alert: "Explanation message on the event reservation page"
|
||||||
|
space_explications_alert: "Explanation message on the space reservation page"
|
||||||
|
visibility_yearly: "Maximum visibility for annual subscribers"
|
||||||
|
visibility_others: "Maximum visibility for other members"
|
||||||
|
display_name_enable: "Display names in the calendar"
|
||||||
|
machines_sort_by: "Machines display order"
|
||||||
|
accounting_journal_code: "Journal code"
|
||||||
|
accounting_card_client_code: "Card clients code"
|
||||||
|
accounting_card_client_label: "Card clients label"
|
||||||
|
accounting_wallet_client_code: "Wallet clients code"
|
||||||
|
accounting_wallet_client_label: "Wallet clients label"
|
||||||
|
accounting_other_client_code: "Other means client code"
|
||||||
|
accounting_other_client_label: "Other means client label"
|
||||||
|
accounting_wallet_code: "Wallet code"
|
||||||
|
accounting_wallet_label: "Wallet label"
|
||||||
|
accounting_VAT_code: "VAT code"
|
||||||
|
accounting_VAT_label: "VAT label"
|
||||||
|
accounting_subscription_code: "Subscriptions code"
|
||||||
|
accounting_subscription_label: "Subscriptions label"
|
||||||
|
accounting_Machine_code: "Machines code"
|
||||||
|
accounting_Machine_label: "Machines label"
|
||||||
|
accounting_Training_code: "Trainings code"
|
||||||
|
accounting_Training_label: "Trainings label"
|
||||||
|
accounting_Event_code: "Events code"
|
||||||
|
accounting_Event_label: "Events label"
|
||||||
|
accounting_Space_code: "Spaces code"
|
||||||
|
accounting_Space_label: "Spaces label"
|
||||||
|
hub_last_version: "Last Fab-manager's version"
|
||||||
|
hub_public_key: "Instance public key"
|
||||||
|
fab_analytics: "Fab Analytics"
|
||||||
|
link_name: "Link title to the \"About\" page"
|
||||||
|
home_content: "The home page"
|
||||||
|
home_css: "Stylesheet of the home page"
|
||||||
|
origin: "Instance URL"
|
||||||
|
uuid: "Instance ID"
|
||||||
|
phone_required: "Phone required?"
|
||||||
|
tracking_id: "Tracking ID"
|
||||||
|
book_overlapping_slots: "Book overlapping slots"
|
||||||
|
slot_duration: "Default duration of booking slots"
|
||||||
|
events_in_calendar: "Display events in the calendar"
|
||||||
|
spaces_module: "Spaces module"
|
||||||
|
plans_module: "Plans modules"
|
||||||
|
invoicing_module: "Invoicing module"
|
||||||
|
facebook_app_id: "Facebook App ID"
|
||||||
|
twitter_analytics: "Twitter analytics account"
|
||||||
|
recaptcha_site_key: "reCAPTCHA Site Key"
|
||||||
|
recaptcha_secret_key: "reCAPTCHA Secret Key"
|
||||||
|
feature_tour_display: "Feature tour display mode"
|
||||||
|
email_from: "Expeditor's address"
|
||||||
|
disqus_shortname: "Disqus shortname"
|
||||||
|
allowed_cad_extensions: "Allowed CAD files extensions"
|
||||||
|
allowed_cad_mime_types: "Allowed CAD files MIME types"
|
||||||
|
openlab_app_id: "OpenLab ID"
|
||||||
|
openlab_app_secret: "OpenLab secret"
|
||||||
|
openlab_default: "Default projects gallery view"
|
||||||
|
online_payment_module: "Online payments module"
|
||||||
|
stripe_public_key: "Stripe public key"
|
||||||
|
stripe_secret_key: "Stripe secret key"
|
||||||
|
stripe_currency: "Stripe currency"
|
||||||
|
invoice_prefix: "Invoices' files prefix"
|
||||||
|
confirmation_required: "Confirmation required"
|
||||||
|
wallet_module: "Wallet module"
|
||||||
|
statistics_module: "Statistics module"
|
||||||
|
upcoming_events_shown: "Display limit for upcoming events"
|
||||||
|
payment_schedule_prefix: "Payment schedule's files prefix"
|
||||||
|
trainings_module: "Trainings module"
|
||||||
|
address_required: "Address required"
|
||||||
|
accounting_Error_code: "Errors code"
|
||||||
|
accounting_Error_label: "Errors label"
|
||||||
|
payment_gateway: "Payment gateway"
|
||||||
|
payzen_username: "PayZen username"
|
||||||
|
payzen_password: "PayZen password"
|
||||||
|
payzen_endpoint: "PayZen API endpoint"
|
||||||
|
payzen_public_key: "PayZen client public key"
|
||||||
|
payzen_hmac: "PayZen HMAC-SHA-256 key"
|
||||||
|
payzen_currency: "PayZen currency"
|
||||||
|
@ -414,3 +414,12 @@ fr:
|
|||||||
group:
|
group:
|
||||||
#name of the user's group for administrators
|
#name of the user's group for administrators
|
||||||
admins: 'Administrateurs'
|
admins: 'Administrateurs'
|
||||||
|
settings:
|
||||||
|
locked_setting: "le paramètre est verrouillé."
|
||||||
|
payment_gateway: "Passerelle de paiement"
|
||||||
|
payzen_username: "Nom d'utilisateur PayZen"
|
||||||
|
payzen_password: "Mot de passe PayZen"
|
||||||
|
payzen_endpoint: "Point d'accès à l'API PayZen"
|
||||||
|
payzen_public_key: "Clef publique du client PayZen"
|
||||||
|
payzen_hmac: "Clef HMAC-SHA-256 PayZen"
|
||||||
|
payzen_currency: "Devise PayZen"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user