diff --git a/app/assets/javascripts/controllers/admin/members.coffee.erb b/app/assets/javascripts/controllers/admin/members.coffee.erb index 008cc7ca8..2c243e738 100644 --- a/app/assets/javascripts/controllers/admin/members.coffee.erb +++ b/app/assets/javascripts/controllers/admin/members.coffee.erb @@ -260,8 +260,8 @@ Application.Controllers.controller "AdminMembersController", ["$scope", 'members ## # Controller used in the member edition page ## -Application.Controllers.controller "EditMemberController", ["$scope", "$state", "$stateParams", "Member", 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise' -, ($scope, $state, $stateParams, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise) -> +Application.Controllers.controller "EditMemberController", ["$scope", "$state", "$stateParams", "Member", 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise', 'Wallet' +, ($scope, $state, $stateParams, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, Wallet) -> @@ -403,6 +403,39 @@ Application.Controllers.controller "EditMemberController", ["$scope", "$state", $scope.subscription = subscription + $scope.createWalletCreditModal = (user, wallet)-> + modalInstance = $uibModal.open + animation: true, + templateUrl: '<%= asset_path "wallet/credit_modal.html" %>' + controller: ['$scope', '$uibModalInstance', 'Wallet', '$locale', ($scope, $uibModalInstance, Wallet, $locale) -> + + ## currency symbol for the current locale (cf. angular-i18n) + $scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM + + ## + # Modal dialog validation callback + ## + $scope.ok = -> + Wallet.credit { id: wallet.id }, { amount: $scope.amount }, (_wallet)-> + + growl.success(_t('wallet_credit_successfully')) + $uibModalInstance.close(_wallet) + , (error)-> + growl.error(_t('a_problem_occurred_for_wallet_credit')) + + ## + # Modal dialog cancellation callback + ## + $scope.cancel = -> + $uibModalInstance.dismiss('cancel') + ] + # once the form was validated succesfully ... + modalInstance.result.then (wallet) -> + $scope.wallet = wallet + Wallet.transactions {id: wallet.id}, (transactions) -> + $scope.transactions = transactions + + ### PRIVATE SCOPE ### diff --git a/app/assets/javascripts/services/wallet.coffee b/app/assets/javascripts/services/wallet.coffee index e3d5c7380..a44326683 100644 --- a/app/assets/javascripts/services/wallet.coffee +++ b/app/assets/javascripts/services/wallet.coffee @@ -15,4 +15,8 @@ Application.Services.factory 'Wallet', ["$resource", ($resource)-> method: 'GET' url: '/api/wallet/:id/transactions' isArray: true + credit: + method: 'PUT' + url: '/api/wallet/:id/credit' + isArray: false ] diff --git a/app/assets/stylesheets/app.components.scss b/app/assets/stylesheets/app.components.scss index e668b9e51..babf2b8bb 100644 --- a/app/assets/stylesheets/app.components.scss +++ b/app/assets/stylesheets/app.components.scss @@ -539,3 +539,23 @@ padding: 10px; } } +.amountGroup { + input { + display: inline-block; + width: 100px; + margin-left: 5px; + padding-right: 6px; + font-weight: bold; + color: $green; + font-size: 1.2em; + line-height: 0; + } + .afterAmount { + margin-left: -35px; + font-weight: bold; + color: $green; + font-size: 1.2em; + line-height: 0; + } +} + diff --git a/app/assets/templates/admin/members/edit.html.erb b/app/assets/templates/admin/members/edit.html.erb index ed5368a2e..7b706e0ec 100644 --- a/app/assets/templates/admin/members/edit.html.erb +++ b/app/assets/templates/admin/members/edit.html.erb @@ -219,6 +219,12 @@
+ +
+
+ +
+
diff --git a/app/assets/templates/wallet/credit_modal.html.erb b/app/assets/templates/wallet/credit_modal.html.erb new file mode 100644 index 000000000..ac98cdb0d --- /dev/null +++ b/app/assets/templates/wallet/credit_modal.html.erb @@ -0,0 +1,20 @@ + + + diff --git a/app/controllers/api/wallet_controller.rb b/app/controllers/api/wallet_controller.rb index 697279bd8..c62672b5a 100644 --- a/app/controllers/api/wallet_controller.rb +++ b/app/controllers/api/wallet_controller.rb @@ -17,4 +17,15 @@ class API::WalletController < API::ApiController authorize @wallet @wallet_transactions = @wallet.wallet_transactions.includes(:transactable, user: [:profile]).order(created_at: :desc) end + + def credit + @wallet = Wallet.find(params[:id]) + authorize @wallet + service = WalletService.new(user: current_user, wallet: @wallet) + if service.credit(params[:amount].to_f) + render :show + else + head 422 + end + end end diff --git a/app/models/notification_type.rb b/app/models/notification_type.rb index 38e8376f8..bbdf3e484 100644 --- a/app/models/notification_type.rb +++ b/app/models/notification_type.rb @@ -37,5 +37,7 @@ class NotificationType notify_admin_profile_complete notify_admin_abuse_reported notify_admin_invoicing_changed + notify_user_wallet_is_credited + notify_admin_user_wallet_is_credited ) end diff --git a/app/policies/wallet_policy.rb b/app/policies/wallet_policy.rb index b3f849b11..edc737386 100644 --- a/app/policies/wallet_policy.rb +++ b/app/policies/wallet_policy.rb @@ -6,4 +6,8 @@ class WalletPolicy < ApplicationPolicy def transactions? user.is_admin? or user == record.user end + + def credit? + user.is_admin? + end end diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 62e657c98..237804928 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -6,7 +6,14 @@ class WalletService def credit(amount) if @wallet.credit(amount) - WalletTransaction.create(user: @user, wallet: @wallet, transaction_type: 'credit', amount: amount) + transaction = WalletTransaction.create(user: @user, wallet: @wallet, transaction_type: 'credit', amount: amount) + + NotificationCenter.call type: 'notify_user_wallet_is_credited', + receiver: @wallet.user, + attached_object: transaction + NotificationCenter.call type: 'notify_admin_user_wallet_is_credited', + receiver: User.admins, + attached_object: transaction return true end end diff --git a/app/views/api/notifications/_notify_admin_user_wallet_is_credited.json.jbuilder b/app/views/api/notifications/_notify_admin_user_wallet_is_credited.json.jbuilder new file mode 100644 index 000000000..6b692d542 --- /dev/null +++ b/app/views/api/notifications/_notify_admin_user_wallet_is_credited.json.jbuilder @@ -0,0 +1,7 @@ +json.title notification.notification_type +amount = notification.attached_object.amount +json.description t('.wallet_is_credited', + AMOUNT: number_to_currency(amount), + USER: notification.attached_object.wallet.user.profile.full_name, + ADMIN: notification.attached_object.user.profile.full_name) +json.url notification_url(notification, format: :json) diff --git a/app/views/api/notifications/_notify_user_wallet_is_credited.json.jbuilder b/app/views/api/notifications/_notify_user_wallet_is_credited.json.jbuilder new file mode 100644 index 000000000..836492cf5 --- /dev/null +++ b/app/views/api/notifications/_notify_user_wallet_is_credited.json.jbuilder @@ -0,0 +1,5 @@ +json.title notification.notification_type +amount = notification.attached_object.amount +json.description t('.your_wallet_is_credited', + AMOUNT: number_to_currency(amount)) +json.url notification_url(notification, format: :json) diff --git a/app/views/notifications_mailer/notify_admin_user_wallet_is_credited.html.erb b/app/views/notifications_mailer/notify_admin_user_wallet_is_credited.html.erb new file mode 100644 index 000000000..8f758a2c8 --- /dev/null +++ b/app/views/notifications_mailer/notify_admin_user_wallet_is_credited.html.erb @@ -0,0 +1,9 @@ +<%# this is a mail template of notifcation notify_admin_user_wallet_is_credited %> +<%= render 'notifications_mailer/shared/hello', recipient: @recipient %> +

+ <%= t('.body.wallet_credit_html', + AMOUNT: number_to_currency(@attached_object.amount), + USER: @attached_object.wallet.user.profile.full_name, + ADMIN: @attached_object.user.profile.full_name) + %> +

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

<%= t('.body.wallet_credit_html', AMOUNT: number_to_currency(@attached_object.amount)) %>

diff --git a/config/locales/app.shared.en.yml b/config/locales/app.shared.en.yml index 7c655ba36..190386259 100644 --- a/config/locales/app.shared.en.yml +++ b/config/locales/app.shared.en.yml @@ -304,4 +304,7 @@ en: operation: 'Operation' operator: 'Operator' amount: 'Amount' - credit: 'Crédit' + credit: 'Credit' + to_credit: 'Credit' + wallet_credit_successfully: "Wallet of user is credited successfully." + a_problem_occurred_for_wallet_credit: "A problem is occurred while taking the credit of wallet" diff --git a/config/locales/app.shared.fr.yml b/config/locales/app.shared.fr.yml index 7215c8599..6eee7821a 100644 --- a/config/locales/app.shared.fr.yml +++ b/config/locales/app.shared.fr.yml @@ -305,3 +305,8 @@ fr: operator: 'Opérateur' amount: 'Montant' credit: 'Crédit' + to_credit: 'Créditer' + wallet_credit_successfully: "Le porte-monnaie d'utilisateur a été chargé avec succès." + a_problem_occurred_for_wallet_credit: "Il y a eu un problème lors de chargement au porte-monnaie d'utilisateur." + amount_is_required: "Le montant est obligatoire" + amount_minimum_1: "Le montant minimum est d'1" diff --git a/config/locales/en.yml b/config/locales/en.yml index 32afecb9f..0e50e0059 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -229,6 +229,10 @@ en: undefined_notification: unknown_notification: "Unknown notification" notification_ID_wrong_type_TYPE_unknown: "Notification %{ID} wrong (type %{TYPE} unknown)" + notify_user_wallet_is_credited: + your_wallet_is_credited: "Your wallet is credited" + notify_admin_user_wallet_is_credited: + wallet_is_credited: "The wallet of %{USER} is credited %{AMOUNT}" statistics: # statistics tools for admins diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 6f93733f6..607c419fd 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -229,6 +229,10 @@ fr: undefined_notification: unknown_notification: "Notification inconnue" notification_ID_wrong_type_TYPE_unknown: "Notification {ID} erronée (type {TYPE} inconnu)." + notify_user_wallet_is_credited: + your_wallet_is_credited: "Votre porte-monnaie est chargé %{AMOUNT}" + notify_admin_user_wallet_is_credited: + wallet_is_credited: "Le porte-monnaie de %{USER} est chargé %{AMOUNT}" statistics: # outil de statistiques pour les administrateurs diff --git a/config/locales/mails.en.yml b/config/locales/mails.en.yml index 8ec076374..ba37e145f 100644 --- a/config/locales/mails.en.yml +++ b/config/locales/mails.en.yml @@ -240,5 +240,15 @@ en: disabled: "From now on, no invoice will be issued when the user pays at the reception." enabled: "From now on, all payments made by this user at the reception will lead to invoicing issuing. " + notify_user_wallet_is_credited: + subject: "Your wallet is credited" + body: + wallet_credit_html: "Your wallet is credited %{AMOUNT}." + + notify_admin_user_wallet_is_credited: + subject: "The wallet of an user is credited" + body: + wallet_credit_html: "The wallet of %{USER} is credited %{AMOUNT} by %{ADMIN}." + shared: hello: "Hello %{user_name}" diff --git a/config/locales/mails.fr.yml b/config/locales/mails.fr.yml index 2f18c1ac3..63fb6fe4c 100644 --- a/config/locales/mails.fr.yml +++ b/config/locales/mails.fr.yml @@ -240,5 +240,15 @@ fr: disabled: "Désormais, aucune facture ne sera générée pour les paiement de cet utilisateur effectués à l'accueil." enabled: "Désormais, tous les paiement de cet utilisateur effectués à l'accueil, donneront lieu à la génération d'une facture." + notify_user_wallet_is_credited: + subject: "Votre porte-monnaie est chargé" + body: + wallet_credit_html: "Votre porte-monnaie est chargé %{AMOUNT}." + + notify_admin_user_wallet_is_credited: + subject: "Le porte-monnaie d'un utilisateur est chargé" + body: + wallet_credit_html: "Le porte-monnaie de %{USER} est chargé %{AMOUNT} par %{ADMIN}." + shared: hello: "Bonjour %{user_name}" diff --git a/config/routes.rb b/config/routes.rb index 02d730d0a..0d90fc87e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -52,6 +52,7 @@ Rails.application.routes.draw do get :my, on: :collection get '/by_user/:user_id', action: 'by_user', on: :collection get :transactions, on: :member + put :credit, on: :member end # for homepage diff --git a/test/integration/wallets_test.rb b/test/integration/wallets_test.rb index be1035b96..05c56fd39 100644 --- a/test/integration/wallets_test.rb +++ b/test/integration/wallets_test.rb @@ -56,4 +56,23 @@ class WalletsTest < ActionDispatch::IntegrationTest get "/api/wallet/#{user5.wallet.id}/transactions" assert_equal 403, response.status end + + test 'admin can credit amount to a wallet' do + admin = users(:user_1) + login_as(admin, scope: :user) + w = @kdumas.wallet + amount = 10 + expected_amount = w.amount + amount + put "/api/wallet/#{w.id}/credit", + { + amount: amount + } + + assert_equal 200, response.status + assert_equal Mime::JSON, response.content_type + wallet = json_response(response.body) + w.reload + assert_equal w.amount, expected_amount + assert_equal w.amount, wallet[:amount] + end end