mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +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
|
||||
@setting = Setting.find_or_initialize_by(name: params[:name])
|
||||
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)
|
||||
SettingService.after_update(@setting)
|
||||
@ -26,18 +26,21 @@ class API::SettingsController < API::ApiController
|
||||
authorize Setting
|
||||
|
||||
@settings = []
|
||||
params[:settings].each do |setting|
|
||||
next if !setting[:name] || !setting[:value]
|
||||
may_transaction(params[:transactional]) do
|
||||
params[:settings].each do |setting|
|
||||
next if !setting[:name] || !setting[:value]
|
||||
|
||||
db_setting = Setting.find_or_initialize_by(name: setting[:name])
|
||||
next unless SettingService.before_update(db_setting)
|
||||
db_setting = Setting.find_or_initialize_by(name: setting[:name])
|
||||
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
|
||||
db_setting.history_values.create(value: setting[:value], invoicing_profile: current_user.invoicing_profile)
|
||||
SettingService.after_update(db_setting)
|
||||
@settings.push db_setting
|
||||
may_rollback(params[:transactional]) if db_setting.errors.keys.count.positive?
|
||||
end
|
||||
|
||||
@settings.push db_setting
|
||||
end
|
||||
end
|
||||
|
||||
@ -79,4 +82,20 @@ class API::SettingsController < API::ApiController
|
||||
def names_as_string_to_array
|
||||
params[:names][1..-2].split(',').map(&:strip).map { |param| param[1..-2] }.map(&:strip)
|
||||
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
|
||||
|
@ -23,8 +23,8 @@ export default class SettingAPI {
|
||||
return res?.data?.setting;
|
||||
}
|
||||
|
||||
async bulkUpdate (settings: Map<SettingName, any>): Promise<Map<SettingName, SettingBulkResult>> {
|
||||
const res: AxiosResponse = await apiClient.patch('/api/settings/bulk_update', { settings: SettingAPI.toObjectArray(settings) });
|
||||
async bulkUpdate (settings: Map<SettingName, any>, transactional: boolean = false): Promise<Map<SettingName, SettingBulkResult>> {
|
||||
const res: AxiosResponse = await apiClient.patch(`/api/settings/bulk_update?transactional=${transactional}`, { settings: SettingAPI.toObjectArray(settings) });
|
||||
return SettingAPI.toBulkMap(res?.data?.settings);
|
||||
}
|
||||
|
||||
@ -67,6 +67,9 @@ export default class SettingAPI {
|
||||
if ('value' in item) {
|
||||
itemData.value = item.value;
|
||||
}
|
||||
if ('localized' in item) {
|
||||
itemData.localized = item.localized;
|
||||
}
|
||||
|
||||
map.set(item.name as SettingName, itemData)
|
||||
});
|
||||
|
@ -23,7 +23,7 @@ interface SelectGatewayModalModalProps {
|
||||
isOpen: boolean,
|
||||
toggleModal: () => void,
|
||||
currentUser: User,
|
||||
onError: (errors: Map<SettingName, SettingBulkResult>|any) => void,
|
||||
onError: (errors: string) => void,
|
||||
onSuccess: (results: Map<SettingName, SettingBulkResult>) => void,
|
||||
}
|
||||
|
||||
@ -102,10 +102,12 @@ const SelectGatewayModal: React.FC<SelectGatewayModalModalProps> = ({ isOpen, to
|
||||
settings.set(SettingName.PaymentGateway, selectedGateway);
|
||||
|
||||
const api = new SettingAPI();
|
||||
api.bulkUpdate(settings).then(result => {
|
||||
if (Array.from(result.values()).filter(item => !item.status).length > 0) {
|
||||
onError(result);
|
||||
api.bulkUpdate(settings, true).then(result => {
|
||||
const errorResults = Array.from(result.values()).filter(item => !item.status);
|
||||
if (errorResults.length > 0) {
|
||||
onError(errorResults.map(item => item.error[0]).join(' '));
|
||||
} else {
|
||||
// we call the success callback only in case of full success (transactional bulk update)
|
||||
onSuccess(result);
|
||||
}
|
||||
}, reason => {
|
||||
|
@ -720,9 +720,8 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
/**
|
||||
* Callback triggered after the gateway failed to be configured
|
||||
*/
|
||||
$scope.onGatewayModalError = function (errors) {
|
||||
growl.error(_t('app.admin.invoices.payment.gateway_configuration_error'));
|
||||
console.error(errors);
|
||||
$scope.onGatewayModalError = function (message) {
|
||||
growl.error(_t('app.admin.invoices.payment.gateway_configuration_error') + message);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,6 @@ export enum SettingName {
|
||||
InvoiceLegals = 'invoice_legals',
|
||||
BookingWindowStart = 'booking_window_start',
|
||||
BookingWindowEnd = 'booking_window_end',
|
||||
BookingSlotDuration = 'booking_slot_duration',
|
||||
BookingMoveEnable = 'booking_move_enable',
|
||||
BookingMoveDelay = 'booking_move_delay',
|
||||
BookingCancelEnable = 'booking_cancel_enable',
|
||||
@ -113,6 +112,7 @@ export enum SettingName {
|
||||
|
||||
export interface Setting {
|
||||
name: SettingName,
|
||||
localized?: string,
|
||||
value: string,
|
||||
last_update?: Date,
|
||||
history?: Array<HistoryValue>
|
||||
@ -127,5 +127,6 @@ export interface SettingError {
|
||||
export interface SettingBulkResult {
|
||||
status: boolean,
|
||||
value?: any,
|
||||
error?: string
|
||||
error?: string,
|
||||
localized?: string,
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
class Setting < ApplicationRecord
|
||||
has_many :history_values
|
||||
# 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:
|
||||
{ in: %w[about_title
|
||||
about_body
|
||||
@ -32,7 +32,6 @@ class Setting < ApplicationRecord
|
||||
invoice_legals
|
||||
booking_window_start
|
||||
booking_window_end
|
||||
booking_slot_duration
|
||||
booking_move_enable
|
||||
booking_move_delay
|
||||
booking_cancel_enable
|
||||
|
@ -34,7 +34,7 @@ class SettingPolicy < ApplicationPolicy
|
||||
def self.public_whitelist
|
||||
%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
|
||||
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
|
||||
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
|
||||
|
@ -1 +1,4 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
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_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"
|
||||
gateway_configuration_error: "An error occurred while configuring the payment gateway."
|
||||
gateway_configuration_error: "An error occurred while configuring the payment gateway: "
|
||||
payzen:
|
||||
payzen_keys: "PayZen keys"
|
||||
payzen_username: "Username"
|
||||
@ -673,6 +673,7 @@ en:
|
||||
stripe: "Stripe"
|
||||
payzen: "PayZen"
|
||||
confirm_button: "Validate the gateway"
|
||||
successfully_updated: " successfully updated"
|
||||
payment_schedules:
|
||||
filter_schedules: "Filter schedules"
|
||||
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_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"
|
||||
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_keys: "Clefs PayZen"
|
||||
payzen_username: "Utilisateur"
|
||||
|
@ -414,3 +414,114 @@ en:
|
||||
group:
|
||||
#name of the user's group for 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:
|
||||
#name of the user's group for administrators
|
||||
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