1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-11-28 09:24:24 +01:00

send a coupon to a user

This commit is contained in:
Sylvain 2016-08-16 18:12:13 +02:00
parent 3253290860
commit 428b2db0ea
20 changed files with 152 additions and 29 deletions

View File

@ -351,10 +351,26 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
resolve:
coupon: -> coupon
size: 'md'
controller: ['$scope', '$uibModalInstance', 'Coupon', 'coupon', ($scope, $uibModalInstance, Coupon, coupon) ->
controller: ['$scope', '$uibModalInstance', 'Coupon', 'coupon', '_t', ($scope, $uibModalInstance, Coupon, coupon, _t) ->
## Member, receiver of the coupon
$scope.ctrl =
member: null
## Details of the coupon to send
$scope.coupon = coupon
## Callback to validate sending of the coupon
$scope.ok = ->
$uibModalInstance.close(user)
Coupon.send {coupon_code: coupon.code, user_id: $scope.ctrl.member.id}, (res) ->
growl.success(_t('coupon_successfully_sent_to_USER', {USER: $scope.ctrl.member.name}))
$uibModalInstance.close({user_id: $scope.ctrl.member.id})
, (err) ->
growl.error(_t('an_error_occurred_unable_to_send_the_coupon'))
## Callback to close the modal and cancel the sending process
$scope.cancel = ->
$uibModalInstance.dismiss('cancel')
]

View File

@ -233,3 +233,28 @@ Application.Filters.filter 'toIsoDate', [ ->
moment(date).format('YYYY-MM-DD')
]
Application.Filters.filter 'booleanFormat', [ '_t', (_t) ->
(boolean) ->
if boolean or boolean == 'true'
_t('yes')
else
_t('no')
]
Application.Filters.filter 'booleanFormat', [ '_t', (_t) ->
(boolean) ->
if (typeof boolean == 'boolean' and boolean) or (typeof boolean == 'string' and boolean == 'true')
_t('yes')
else
_t('no')
]
Application.Filters.filter 'maxCount', [ '_t', (_t) ->
(max) ->
if typeof max == 'undefined' or max == null or (typeof max == 'number' and max == 0)
_t('unlimited')
else
max
]

View File

@ -8,4 +8,7 @@ Application.Services.factory 'Coupon', ["$resource", ($resource)->
validate:
method: 'POST'
url: '/api/coupons/validate'
send:
method: 'POST'
url: '/api/coupons/send'
]

View File

@ -1,31 +1,30 @@
<div class="modal-header">
<img ng-src="{{logoBlack.custom_asset_file_attributes.attachment_url}}" alt="{{logo.custom_asset_file_attributes.attachment}}" class="modal-logo"/>
<h1 translate>{{ 'send_a_coupon' }}</h1>
<h3 class="text-center red" translate>{{ 'send_a_coupon' }}</h3>
</div>
<div class="">
<div class="well m-b-n">
<select-member></select-member>
<div class="widget panel b-a m">
<div class="panel-heading b-b small">
<h3 class="panel-title" translate>{{ 'coupon' }}</h3>
</div>
<div class="widget-content no-bg auto wrapper">
<table>
<thead>
<tr><th style="width:60%"></th></tr>
</thead>
<tbody>
<tr><td translate>{{'code'}}</td><td>{{coupon.code}}</td></tr>
<tr><td translate>{{'percent_off'}}</td><td>{{coupon.percent_off}} %</td></tr>
<tr><td translate>{{'validity_per_user'}}</td><td translate>{{coupon.validity_per_user}}</td></tr>
<tr><td translate>{{'valid_until'}}</td><td>{{coupon.valid_until | amDateFormat:'L'}}</td></tr>
</tbody>
</table>
</div>
<div class="modal-body">
<select-member></select-member>
<div class="widget panel b-a m">
<div class="panel-heading b-b small">
<h3 class="panel-title" translate>{{ 'coupon' }}</h3>
</div>
<div class="widget-content no-bg auto wrapper">
<table>
<thead>
<tr><th style="width:60%"></th></tr>
</thead>
<tbody>
<tr><td translate>{{'code'}}</td><td>{{coupon.code}}</td></tr>
<tr><td translate>{{'percent_off'}}</td><td>{{coupon.percent_off}} %</td></tr>
<tr><td translate>{{'validity_per_user'}}</td><td translate>{{coupon.validity_per_user}}</td></tr>
<tr><td translate>{{'valid_until'}}</td><td>{{coupon.valid_until | amDateFormat:'L'}}</td></tr>
<tr><td translate>{{'usages'}}</td><td>{{coupon.usages}} / {{coupon.max_usages | maxCount}}</td></tr>
<tr><td translate>{{'enabled'}}</td><td>{{coupon.active | booleanFormat}}</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="modal-footer no-padder">
<button class="btn btn-valid btn-warning btn-block p-l btn-lg text-u-c r-b" ng-click="ok()" translate>{{ 'confirm' }}</button>
<div class="modal-footer">
<button class="btn btn-warning" ng-click="ok()" ng-disabled="ctrl.member == null" translate>{{ 'confirm' }}</button>
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'cancel' }}</button>
</div>

View File

@ -57,6 +57,21 @@ class API::CouponsController < API::ApiController
end
end
def send_to
authorize Coupon
@coupon = Coupon.find_by_code(params[:coupon_code])
if @coupon.nil?
render json: {error: "no coupon with code #{params[:coupon_code]}"}, status: :not_found
else
if @coupon.send_to(params[:user_id])
render :show, status: :ok, location: @coupon
else
render json: @coupon.errors, status: :unprocessable_entity
end
end
end
private
def set_coupon
@coupon = Coupon.find(params[:id])

View File

@ -58,6 +58,12 @@ class Coupon < ActiveRecord::Base
end
end
def send_to(user_id)
NotificationCenter.call type: 'notify_member_about_coupon',
receiver: User.find(user_id),
attached_object: self
end
def create_stripe_coupon
StripeWorker.perform_async(:create_stripe_coupon, id)
end

View File

@ -40,5 +40,6 @@ class NotificationType
notify_user_wallet_is_credited
notify_admin_user_wallet_is_credited
notify_admin_export_complete
notify_member_about_coupon
)
end

View File

@ -1,5 +1,5 @@
class CouponPolicy < ApplicationPolicy
%w(index show create update destroy).each do |action|
%w(index show create update destroy send_to).each do |action|
define_method "#{action}?" do
user.is_admin?
end

View File

@ -0,0 +1,5 @@
json.title notification.notification_type
json.description t('.enjoy_a_discount_of_PERCENT_with_code_CODE',
PERCENT: notification.attached_object.percent_off,
CODE: notification.attached_object.code)
json.url notification_url(notification, format: :json)

View File

@ -0,0 +1,28 @@
<%= render 'notifications_mailer/shared/hello', recipient: @recipient %>
<p><%= t('.body.enjoy_a_discount_of_PERCENT_with_code_CODE',
PERCENT: @attached_object.percent_off,
CODE: @attached_object.code
) %>
</p>
<%
# we must tell the use if he could use the code just once or many times (in case we won't specify)
usages = 999 # just a number > 1
if @attached_object.validity_per_user == 'once'
usages = 1
else
unless @attached_object.max_usages.nil?
usages = @attached_object.max_usages
end
end
%>
<p>
<%= _t('.body.this_coupon_is_valid_USAGE_times_until_DATE_for_all_your_purchases',
{
USAGE: usages,
DATE: @attached_object.valid_until.nil? ? 'NO-DATE' : I18n.l(@attached_object.valid_until.to_date)
})
# messageFormat
%>
</p>

View File

@ -27,7 +27,7 @@ class StripeWorker
end
stp_coupon
unless coupon.max_usages.nil?
stp_coupon[max_redemptions] = coupon.max_usages
stp_coupon[:max_redemptions] = coupon.max_usages
end
Stripe::Coupon.create(stp_coupon)

View File

@ -160,6 +160,9 @@ en:
unable_to_delete_the_specified_coupon_an_unexpected_error_occurred: "Unable to delete the specified coupon: an unexpected error occurred."
send_a_coupon: "Send a coupon"
coupon: "Coupon"
usages: "Usages"
coupon_successfully_sent_to_USER: "Coupon successfully sent to {{USER}}" # angular interpolation
an_error_occurred_unable_to_send_the_coupon: "An unexpected error prevent from sending the coupon."
coupons_new:
# ajouter un code promotionnel

View File

@ -160,6 +160,9 @@ fr:
unable_to_delete_the_specified_coupon_an_unexpected_error_occurred: "Impossible de supprimer le code promotionnel : une erreur inattendue s'est produite."
send_a_coupon: "Envoyer un code promo"
coupon: "Code promo"
usages: "Utilisations"
coupon_successfully_sent_to_USER: "Le code promotionnel a bien été envoyé à {{USER}}" # angular interpolation
an_error_occurred_unable_to_send_the_coupon: "Une erreur inattendue a empêché l'envoi du code promotionnel."
coupons_new:
# ajouter un code promotionnel

View File

@ -101,6 +101,7 @@ en:
share_on_facebook: "Share on Facebook"
share_on_twitter: "Share on Twitter"
incomplete_profile: "Incomplete profile"
unlimited: "Unlimited"
messages:
you_will_lose_any_unsaved_modification_if_you_quit_this_page: "You will lose any unsaved modification if you quit this page"

View File

@ -101,6 +101,7 @@ fr:
share_on_facebook: "Partager sur Facebook"
share_on_twitter: "Partager sur Twitter"
incomplete_profile: "Profil incomplet"
unlimited: "Illimité"
messages:
you_will_lose_any_unsaved_modification_if_you_quit_this_page: "Vous perdrez les modifications non enregistrées si vous quittez cette page"

View File

@ -268,6 +268,8 @@ en:
users_reservations: "of the reservations' list"
is_over: "is over."
download_here: "Download here"
notify_member_about_coupon:
enjoy_a_discount_of_PERCENT_with_code_CODE: "Enjoy a discount of %{PERCENT}% with code %{CODE}"
statistics:
# statistics tools for admins

View File

@ -268,6 +268,8 @@ fr:
users_reservations: "de la liste des réservations"
is_over: "est terminé."
download_here: "Téléchargez ici"
notify_member_about_coupon:
enjoy_a_discount_of_PERCENT_with_code_CODE: "Bénéficiez d'une remise de %{PERCENT} % avec le code %{CODE}"
statistics:
# outil de statistiques pour les administrateurs

View File

@ -268,5 +268,11 @@ en:
click_to_download: "Excel file generated successfully. To download it, click"
here: "here"
notify_member_about_coupon:
subject: "Coupon"
body:
enjoy_a_discount_of_PERCENT_with_code_CODE: "Enjoy a discount of %{PERCENT}% on the whole site with the code %{CODE}."
this_coupon_is_valid_USAGE_times_until_DATE_for_all_your_purchases: "This coupon is valid {USAGE, plural, =1{just once} other{many times}}: for all your purchases, from now {DATE, select, NO-DATE{and without time limit} other{and until {DATE}}}."
shared:
hello: "Hello %{user_name}"

View File

@ -268,5 +268,11 @@ fr:
click_to_download: "La génération est terminée. Pour télécharger le fichier Excel, cliquez"
here: "ici"
notify_member_about_coupon:
subject: "Code promo"
body:
enjoy_a_discount_of_PERCENT_with_code_CODE: "Bénéficiez d'une remise de %{PERCENT} % sur tout le site en utilisant le code promo %{CODE}."
this_coupon_is_valid_USAGE_times_until_DATE_for_all_your_purchases: "Ce code promo est valable {USAGE, plural, =1{une seule fois} other{plusieurs fois}} : pour tous vos achats, dès maintenant {DATE, select, NO-DATE{et sans limitation de durée} other{et jusqu'au {DATE}}}."
shared:
hello: "Bonjour %{user_name}"

View File

@ -71,6 +71,7 @@ Rails.application.routes.draw do
end
resources :coupons
post 'coupons/validate' => 'coupons#validate'
post 'coupons/send' => 'coupons#send_to'
resources :trainings_pricings, only: [:index, :update]