1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-18 07:52:23 +01:00

interface to create new coupons

This commit is contained in:
Sylvain 2016-08-04 18:13:19 +02:00
parent ee03f1a79c
commit 7c434db09a
12 changed files with 236 additions and 21 deletions

View File

@ -0,0 +1,54 @@
##
# Controller used in the coupon creation page
##
Application.Controllers.controller "NewCouponController", ["$scope", "$state",'Coupon', 'growl', '_t'
, ($scope, $state, Coupon, growl, _t) ->
### PUBLIC SCOPE ###
## Values for the coupon currently created
$scope.coupon =
active: true
## Default parameters for AngularUI-Bootstrap datepicker (used for coupon validity limit selection)
$scope.datePicker =
format: Fablab.uibDateFormat
opened: false # default: datePicker is not shown
options:
startingDay: Fablab.weekStartingDay
##
# Shows the validity limit datepicker
# @param $event {Object} jQuery event object
##
$scope.openDatePicker = ($event) ->
$event.preventDefault()
$event.stopPropagation()
$scope.datePicker.opened = true
##
# Callback to save the new coupon in $scope.coupon and redirect the user to the listing page
##
$scope.saveCoupon = ->
Coupon.save coupon: $scope.coupon, (coupon) ->
$state.go('app.admin.pricing')
, (err)->
growl.error(_t('unable_to_create_the_coupon_an_error_occurred'))
console.error(err)
]
##
# Controller used in the coupon edition page
##
Application.Controllers.controller "EditCouponController", ["$scope", 'Coupon', '_t'
, ($scope, Coupon, _t) ->
### PUBLIC SCOPE ###
$scope.test = 'edit'
]

View File

@ -319,9 +319,9 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
$scope.getCouponStatus = (coupon) -> $scope.getCouponStatus = (coupon) ->
unless coupon.active unless coupon.active
return _t('disabled') return _t('disabled')
unless moment(coupon.valid).isSameOrBefore() if coupon.valid_until and moment(coupon.valid_until).isAfter()
return _t('expired') return _t('expired')
unless coupon.usages <= coupon.max_usages if coupon.max_usages and coupon.usages <= coupon.max_usages
return _t('sold_out') return _t('sold_out')
return _t('active') return _t('active')

View File

@ -790,7 +790,7 @@ angular.module('application.router', ['ui.router']).
] ]
# coupons # coupons
.state 'app.admin.coupons.new', .state 'app.admin.coupons_new',
url: '/admin/coupons/new' url: '/admin/coupons/new'
views: views:
'main@': 'main@':
@ -798,9 +798,9 @@ angular.module('application.router', ['ui.router']).
controller: 'NewCouponController' controller: 'NewCouponController'
resolve: resolve:
translations: [ 'Translations', (Translations) -> translations: [ 'Translations', (Translations) ->
Translations.query(['app.admin.coupons.new', 'app.shared.coupon']).$promise Translations.query(['app.admin.coupons_new', 'app.shared.coupon']).$promise
] ]
.state 'app.admin.coupons.edit', .state 'app.admin.coupons_edit',
url: '/admin/coupons/:id/edit' url: '/admin/coupons/:id/edit'
views: views:
'main@': 'main@':
@ -808,7 +808,7 @@ angular.module('application.router', ['ui.router']).
controller: 'EditCouponController' controller: 'EditCouponController'
resolve: resolve:
translations: [ 'Translations', (Translations) -> translations: [ 'Translations', (Translations) ->
Translations.query(['app.admin.coupons.edit', 'app.shared.coupon']).$promise Translations.query(['app.admin.coupons_edit', 'app.shared.coupon']).$promise
] ]

View File

@ -0,0 +1,72 @@
<div class="form-group" ng-class="{'has-error': couponForm['coupon[name]'].$dirty && couponForm['coupon[name]'].$invalid}">
<label for="coupon[name]">{{ 'name' | translate }} *</label>
<input type="text" id="coupon[name]"
name="coupon[name]"
class="form-control"
ng-model="coupon.name"
required="required"/>
<span class="help-block error" ng-show="couponForm['coupon[name]'].$dirty && couponForm['coupon[name]'].$error.required" translate>{{ 'name_is_required' }}</span>
</div>
<div class="form-group" ng-class="{'has-error': couponForm['coupon[code]'].$dirty && couponForm['coupon[code]'].$invalid}">
<label for="coupon[code]">{{ 'code' | translate }} *</label>
<input type="text" id="coupon[code]"
name="coupon[code]"
class="form-control"
ng-model="coupon.code"
ng-pattern="/^[A-Z0-9]+$/"
required="required"/>
<span class="help-block error" ng-show="couponForm['coupon[code]'].$dirty && couponForm['coupon[code]'].$error.required" translate>{{ 'code_is_required' }}</span>
<span class="help-block error" ng-show="couponForm['coupon[code]'].$dirty && couponForm['coupon[code]'].$error.pattern" translate>{{ 'code_must_be_composed_of_capital_letters_and_or_digits' }}</span>
</div>
<div class="form-group" ng-class="{'has-error': couponForm['coupon[percent_off]'].$dirty && couponForm['coupon[percent_off]'].$invalid}">
<label for="coupon[percent_off]">{{ 'percent_off' | translate }} *</label>
<div class="input-group">
<input type="number" id="coupon[percent_off]"
name="coupon[percent_off]"
class="form-control"
ng-model="coupon.percent_off"
min="0"
max="100"
required="required"/>
<span class="input-group-addon"><i class="fa fa-percent"></i></span>
</div>
<span class="help-block error" ng-show="couponForm['coupon[percent_off]'].$dirty && couponForm['coupon[percent_off]'].$error.required" translate>{{ 'percent_off_is_required' }}</span>
<span class="help-block error" ng-show="couponForm['coupon[percent_off]'].$dirty && (couponForm['coupon[percent_off]'].$error.min || couponForm['coupon[percent_off]'].$error.max)" translate>{{ 'percentage_must_be_between_0_and_100' }}</span>
</div>
<div class="form-group">
<label for="coupon[valid_until]" translate>{{ 'valid_until' }}</label>
<input type="text" id="coupon[valid_until]"
name="coupon[valid_until]"
class="form-control"
ng-model="coupon.valid_until"
uib-datepicker-popup="{{datePicker.format}}"
datepicker-options="datePicker.options"
is-open="datePicker.opened"
ng-click="openDatePicker($event)"/>
</div>
<div class="form-group" ng-class="{'has-error': couponForm['coupon[max_usages]'].$dirty && couponForm['coupon[max_usages]'].$invalid}">
<label for="coupon[max_usages]">{{ 'max_usages' | translate }}</label>
<input type="number" id="coupon[max_usages]"
name="coupon[max_usages]"
class="form-control"
ng-model="coupon.max_usages"
min="0"/>
<span class="help-block error" ng-show="couponForm['coupon[max_usages]'].$dirty && couponForm['coupon[max_usages]'].$error.min" translate>{{ 'max_usages_must_be_equal_or_greater_than_0' }}</span>
</div>
<div class="form-group">
<label for="coupon[active]" translate>{{ 'enabled' }}</label>
<input bs-switch
ng-model="coupon.active"
id="coupon[active]"
type="checkbox"
class="form-control"
switch-on-text="{{ 'yes' | translate }}"
switch-off-text="{{ 'no' | translate }}"
switch-animate="true" />
<input type="hidden" name="coupon[active]" value="{{coupon.active}}"/>
</div>

View File

@ -1 +1,40 @@
<ng-include src="'<%= asset_path 'admin/coupons/_coupon.html' %>'"></ng-include> <section class="heading b-b">
<div class="row no-gutter">
<div class="col-xs-2 col-sm-2 col-md-1">
<section class="heading-btn">
<a href="#" ng-click="backPrevLocation($event)"><i class="fa fa-long-arrow-left "></i></a>
</section>
</div>
<div class="col-xs-10 col-sm-10 col-md-8 b-l">
<section class="heading-title">
<h1>{{ 'coupon' | translate }} {{ coupon.name }}</h1>
</section>
</div>
<div class="col-md-3">
<section class="heading-actions wrapper">
<a class="btn btn-lg btn-block btn-default m-t-xs" ui-sref="app.admin.pricing" translate>{{ 'cancel' }}</a>
</section>
</div>
</div>
</section>
<div class="row no-gutter">
<div class=" col-sm-12 col-md-9 b-r nopadding">
<div id="couponForm">
<form name="couponForm" novalidate="novalidate" class="col-lg-7 col-lg-offset-2 m-t-lg form-group">
<ng-include src="'<%= asset_path 'admin/coupons/_form.html' %>'"></ng-include>
<div class="panel-footer no-padder">
<input type="submit" value="{{ 'confirm_changes' | translate }}" class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c" ng-disabled="couponForm.$invalid"/>
</div>
</form>
</div>
</div>
</div>

View File

@ -1 +1,33 @@
<ng-include src="'<%= asset_path 'admin/coupons/_coupon.html' %>'"></ng-include> <section class="heading b-b">
<div class="row no-gutter">
<div class="col-xs-2 col-sm-2 col-md-1">
<section class="heading-btn">
<a href="#" ng-click="backPrevLocation($event)"><i class="fa fa-long-arrow-left "></i></a>
</section>
</div>
<div class="col-xs-10 col-sm-10 col-md-8 b-l">
<section class="heading-title">
<h1 translate>{{ 'add_a_coupon' }}</h1>
</section>
</div>
</div>
</section>
<div class="row no-gutter">
<div class=" col-sm-12 col-md-9 b-r nopadding">
<div id="couponForm">
<form name="couponForm" novalidate="novalidate" class="col-lg-10 col-lg-offset-2 m-t-lg form-group">
<ng-include src="'<%= asset_path 'admin/coupons/_form.html' %>'"></ng-include>
<div class="panel-footer no-padder">
<input type="button" value="{{ 'save' | translate }}" class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c" ng-disabled="couponForm.$invalid" ng-click="saveCoupon()"/>
</div>
</form>
</div>
</div>
</div>

View File

@ -1,12 +1,12 @@
<h2 translate>{{ 'list_of_the_coupons' }}</h2> <h2 translate>{{ 'list_of_the_coupons' }}</h2>
<button type="button" class="btn btn-warning m-t-lg m-b" ui-sref="app.admin.coupons.new" translate>{{ 'add_a_new_coupon' }}</button> <button type="button" class="btn btn-warning m-t-lg m-b" ui-sref="app.admin.coupons_new" translate>{{ 'add_a_new_coupon' }}</button>
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th>{{ 'name' | translate }}</th> <th translate>{{ 'name' }}</th>
<th>{{ 'percentage_off' | translate }}</th> <th translate>{{ 'percentage_off' }}</th>
<th>{{ 'status' | translate }}</th> <th translate>{{ 'status' }}</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
@ -16,7 +16,7 @@
<td>{{coupon.percent_off}} %</td> <td>{{coupon.percent_off}} %</td>
<td>{{getCouponStatus(coupon)}}</td> <td>{{getCouponStatus(coupon)}}</td>
<td> <td>
<button type="button" class="btn btn-default" ui-sref="app.admin.coupons.edit({id:coupon.id})"><i class="fa fa-pencil-square-o"></i></button> <button type="button" class="btn btn-default" ui-sref="app.admin.coupons_edit({id:coupon.id})"><i class="fa fa-pencil-square-o"></i></button>
<button type="button" class="btn btn-danger" ng-click="deleteCoupon(coupons, coupon.id)"><i class="fa fa-trash"></i></button> <button type="button" class="btn btn-danger" ng-click="deleteCoupon(coupons, coupon.id)"><i class="fa fa-trash"></i></button>
</td> </td>
</tr> </tr>

View File

@ -1,8 +1,9 @@
class Coupon < ActiveRecord::Base class Coupon < ActiveRecord::Base
has_many :invoices has_many :invoices
validates :name, presence: true
validates :code, presence: true validates :code, presence: true
validates :code, format: { with: /[A-Z0-9]+/ ,message: 'only caps letters and numbers'} validates :code, format: { with: /\A[A-Z0-9]+\z/ ,message: 'only caps letters and numbers'}
validates :percent_off, presence: true validates :percent_off, presence: true
validates :percent_off, :inclusion => 0..100 validates :percent_off, :inclusion => 0..100

View File

@ -1,2 +1,2 @@
json.extract! coupon, :id, :name, :code, :percent_off, :valid_until, :max_usages, :active, :created_at json.extract! coupon, :id, :name, :code, :percent_off, :valid_until, :max_usages, :active, :created_at
json.usages @coupon.invoices.count json.usages coupon.invoices.count

View File

@ -157,6 +157,11 @@ fr:
coupon_was_successfully_deleted: "Le code promotionnel a bien été supprimé." coupon_was_successfully_deleted: "Le code promotionnel a bien été supprimé."
unable_to_delete_the_specified_coupon_an_error_occurred: "Impossible de supprimer le code promotionnel, une erreur s'est produite." unable_to_delete_the_specified_coupon_an_error_occurred: "Impossible de supprimer le code promotionnel, une erreur s'est produite."
coupons_new:
# ajouter un code promotionnel
add_a_coupon: "Ajouter un code promotionnel"
unable_to_create_the_coupon_an_error_occurred: "Impossible de créer le code promotionnel : une erreur est survenue."
plans: plans:
new: new:
# ajouter une formule d'abonnement sur la plate-forme # ajouter une formule d'abonnement sur la plate-forme

View File

@ -331,3 +331,15 @@ fr:
debit_reservation_training: "Payer un reservation de formation" debit_reservation_training: "Payer un reservation de formation"
debit_reservation_machine: "Payer un reservation de machine" debit_reservation_machine: "Payer un reservation de machine"
debit_reservation_event: "Payer un reservation d'évenement" debit_reservation_event: "Payer un reservation d'évenement"
coupon:
code: "Code"
code_is_required: "Le code est requis."
code_must_be_composed_of_capital_letters_and_or_digits: "Le code doit être composé de lettres majuscules et/ou de chiffres."
percent_off: "Pourcentage de réduction"
percent_off_is_required: "Le pourcentage de réduction est requis."
percentage_must_be_between_0_and_100: "Le pourcentage doit être compris entre 0 et 100."
valid_until: "Valable jusqu'au (inclus)"
max_usages: "Nombre maximum d'utilisations autorisées"
max_usages_must_be_equal_or_greater_than_0: "Le nombre d'utilisations maximum doit être supérieur ou égal à 0."
enabled: "Activé"