From a05ef1f0ba264da032e566d34791e6d5f31f0837 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 25 Jan 2023 16:40:55 +0100 Subject: [PATCH] (feat) auto refund after trainings cancelled and notify --- app/models/notification_type.rb | 1 + app/models/setting.rb | 17 ++++++++--------- app/services/training_service.rb | 19 ++++++++++++++++++- ...dmin_training_auto_cancelled.json.jbuilder | 5 ++++- ...mber_training_auto_cancelled.json.jbuilder | 7 +++++++ ...ify_admin_training_auto_cancelled.html.erb | 3 +++ ...fy_member_training_auto_cancelled.html.erb | 13 +++++++++++++ config/locales/en.yml | 8 +++++++- config/locales/mails.en.yml | 13 ++++++++++--- 9 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 app/views/api/notifications/notify_member_training_auto_cancelled.json.jbuilder create mode 100644 app/views/notifications_mailer/notify_member_training_auto_cancelled.html.erb diff --git a/app/models/notification_type.rb b/app/models/notification_type.rb index 2bd1f4ae3..8eeb3d300 100644 --- a/app/models/notification_type.rb +++ b/app/models/notification_type.rb @@ -74,6 +74,7 @@ class NotificationType notify_user_order_is_refunded notify_admin_low_stock_threshold notify_admin_training_auto_cancelled + notify_member_training_auto_cancelled ] # deprecated: # - notify_member_subscribed_plan_is_changed diff --git a/app/models/setting.rb b/app/models/setting.rb index 900adbef3..56f8b80ab 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -219,11 +219,10 @@ class Setting < ApplicationRecord save && history_values.create(invoicing_profile: admin.invoicing_profile, value: val) end - ## # Return the value of the requested setting, if any. - # Usage: Setting.get('my_setting') - # @return {String|Boolean} - ## + # @example Setting.get('my_setting') #=> "foo" + # @param name [String] + # @return [String,Boolean] def self.get(name) res = find_by('LOWER(name) = ? ', name.downcase)&.value @@ -234,20 +233,20 @@ class Setting < ApplicationRecord res end - ## # Create or update the provided setting with the given value - # Usage: Setting.set('my_setting', true) + # @example Setting.set('my_setting', true) # Optionally (but recommended when possible), the user updating the value can be provided as the third parameter # Eg.: Setting.set('my_setting', true, User.find_by(slug: 'admin')) - ## + # @param name [String] + # @param value [String,Boolean,Numeric,NilClass] def self.set(name, value, user = User.admins.first) setting = find_or_initialize_by(name: name) setting.save && setting.history_values.create(invoicing_profile: user.invoicing_profile, value: value.to_s) end - ## # Check if the given setting was set - ## + # @param name [String] + # @return [Boolean] def self.set?(name) !find_by(name: name)&.value.nil? end diff --git a/app/services/training_service.rb b/app/services/training_service.rb index 1c6287a59..c6b2ef964 100644 --- a/app/services/training_service.rb +++ b/app/services/training_service.rb @@ -28,12 +28,21 @@ class TrainingService .find_each do |availability| next if availability.reservations.count >= training.auto_cancel_threshold + auto_refund = Setting.get('wallet_module') + NotificationCenter.call type: 'notify_admin_training_auto_cancelled', receiver: User.admins_and_managers, - attached_object: availability + attached_object: availability, + meta_data: { auto_refund: auto_refund } availability.slots_reservations.find_each do |sr| + NotificationCenter.call type: 'notify_member_training_auto_cancelled', + receiver: sr.reservation.user, + attached_object: sr, + meta_data: { auto_refund: auto_refund } + sr.update(canceled_at: DateTime.current) + refund_after_cancel(sr.reservation) if auto_refund end end end @@ -80,5 +89,13 @@ class TrainingService state = filters[:public_page] == 'false' ? [nil, false] : true trainings.where(public_page: state) end + + # @param reservation [Reservation] + def refund_after_cancel(reservation) + invoice_item = reservation.invoice_items.joins(:invoice).where(invoices: { type: nil }).first + service = WalletService.new(user: reservation.user, wallet: reservation.user.wallet) + transaction = service.credit(invoice_item.amount_after_coupon / 100.00) + service.create_avoir(transaction, DateTime.current, I18n.t('trainings.refund_for_auto_cancel')) if transaction + end end end diff --git a/app/views/api/notifications/_notify_admin_training_auto_cancelled.json.jbuilder b/app/views/api/notifications/_notify_admin_training_auto_cancelled.json.jbuilder index 604ed266a..1545a3836 100644 --- a/app/views/api/notifications/_notify_admin_training_auto_cancelled.json.jbuilder +++ b/app/views/api/notifications/_notify_admin_training_auto_cancelled.json.jbuilder @@ -1,4 +1,7 @@ # frozen_string_literal: true json.title notification.notification_type -json.description t('.auto_cancelled_training') +json.description "#{t('.auto_cancelled_training', { + TRAINING: notification.attached_object.trainings.first.name, + DATE: I18n.l(notification.attached_object.start_at.to_date) + })} #{notification.meta_data['auto_refund'] == 'true' ? t('.auto_refund') : t('.manual_refund')}" diff --git a/app/views/api/notifications/notify_member_training_auto_cancelled.json.jbuilder b/app/views/api/notifications/notify_member_training_auto_cancelled.json.jbuilder new file mode 100644 index 000000000..af83b627c --- /dev/null +++ b/app/views/api/notifications/notify_member_training_auto_cancelled.json.jbuilder @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +json.title notification.notification_type +json.description "#{t('.auto_cancelled_training', { + TRAINING: notification.attached_object.reservation.reservable.name, + DATE: I18n.l(notification.attached_object.start_at.to_date) + })} #{notification.meta_data['auto_refund'] == 'true' ? t('.auto_refund') : ''}" diff --git a/app/views/notifications_mailer/notify_admin_training_auto_cancelled.html.erb b/app/views/notifications_mailer/notify_admin_training_auto_cancelled.html.erb index 83a365261..f8e04d6e0 100644 --- a/app/views/notifications_mailer/notify_admin_training_auto_cancelled.html.erb +++ b/app/views/notifications_mailer/notify_admin_training_auto_cancelled.html.erb @@ -8,3 +8,6 @@ END: I18n.l(@attached_object.end_at, format: :hour_minute) }) %>

+

+ <%= @notification.get_meta_data(:auto_refund) == 'true' ? t('.body.auto_refund') : t('.body.manual_refund') %> +

diff --git a/app/views/notifications_mailer/notify_member_training_auto_cancelled.html.erb b/app/views/notifications_mailer/notify_member_training_auto_cancelled.html.erb new file mode 100644 index 000000000..cc3da13fe --- /dev/null +++ b/app/views/notifications_mailer/notify_member_training_auto_cancelled.html.erb @@ -0,0 +1,13 @@ +<%= render 'notifications_mailer/shared/hello', recipient: @recipient %> + +

+ <%= t('.body.cancelled_training', { + TRAINING: @attached_object.reservation.reservable.name, + DATE: I18n.l(@attached_object.start_at.to_date), + START: I18n.l(@attached_object.start_at, format: :hour_minute), + END: I18n.l(@attached_object.end_at, format: :hour_minute) + }) %> +

+

+ <%= @notification.get_meta_data(:auto_refund) == 'true' ? t('.body.auto_refund') : '' %> +

diff --git a/config/locales/en.yml b/config/locales/en.yml index 2b0e40f73..1e2d5a992 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -180,6 +180,7 @@ en: trainings: i_ve_reserved: "I've reserved" completed: "Full" + refund_for_auto_cancel: "This training session was cancelled due to an insufficient number of participants." #error messages when updating an event events: error_deleting_reserved_price: "Unable to delete the requested price because it is associated with some reservations" @@ -297,7 +298,9 @@ en: notify_admin_subscription_will_expire_in_7_days: USER_s_subscription_will_expire_in_7_days: "%{USER}'s subscription will expire in 7 days." notify_admin_training_auto_cancelled: - auto_cancelled_training: "TODO" + auto_cancelled_training: "The %{TRAINING} training session scheduled for %{DATE}, has been automatically canceled due to an insufficient number of participants." + auto_refund: "The members were automatically refunded on their wallet." + manual_refund: "Please refund each members." notify_admin_user_group_changed: user_NAME_changed_his_group_html: "User {NAME} changed group." #messageFormat interpolation notify_admin_user_merged: @@ -328,6 +331,9 @@ en: your_subscription_has_expired: "Your subscription has expired." notify_member_subscription_will_expire_in_7_days: your_subscription_will_expire_in_7_days: "Your subscription will expire in 7 days." + notify_member_training_auto_cancelled: + auto_cancelled_training: "The %{TRAINING} training session scheduled for %{DATE}, has been canceled due to an insufficient number of participants." + auto_refund: "You were refunded on your wallet." notify_partner_subscribed_plan: subscription_partner_PLAN_has_been_subscribed_by_USER_html: "Partner subscription %{PLAN} has been subscribed by %{USER}." notify_project_author_when_collaborator_valid: diff --git a/config/locales/mails.en.yml b/config/locales/mails.en.yml index 593c908c7..2251ad5a7 100644 --- a/config/locales/mails.en.yml +++ b/config/locales/mails.en.yml @@ -131,10 +131,11 @@ en: your_plan: "you plan" expires_in_7_days: "will expire in 7 days." to_renew_your_plan_follow_the_link: "Please, follow this link to renew your plan" - notify_admin_training_auto_cancelled: - subject: "A training was automatically cancelled" + notify_member_training_auto_cancelled: + subject: "Your training session was cancelled" body: - cancelled_training: "The %{TRAINING} training session scheduled for %{DATE}, from %{START} to %{END} has been automatically canceled due to an insufficient number of participants." + cancelled_training: "The %{TRAINING} training session scheduled for %{DATE}, from %{START} to %{END} has been canceled due to an insufficient number of participants." + auto_refund: "You were refunded on your wallet and a credit note should be available." notify_member_subscription_is_expired: subject: "Your subscription has expired" body: @@ -146,6 +147,12 @@ en: subject: "A member subscription expires in 7 days" body: subscription_will_expire_html: "Subscription plan for user %{NAME} %{PLAN} will expire in 7 days." + notify_admin_training_auto_cancelled: + subject: "A training was automatically cancelled" + body: + cancelled_training: "The %{TRAINING} training session scheduled for %{DATE}, from %{START} to %{END} has been automatically canceled due to an insufficient number of participants." + auto_refund: "The members who have booked this training session were automatically refunded on their wallet and credit notes was generated." + manual_refund: "Please manually refund all members who have booked this training session and generate the credit notes." notify_admin_subscription_is_expired: subject: "A member subscription has expired" body: