mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-11-29 10:24:20 +01:00
448 lines
15 KiB
Plaintext
448 lines
15 KiB
Plaintext
'use strict'
|
|
|
|
##
|
|
# Controller used in the prices edition page
|
|
##
|
|
Application.Controllers.controller "EditPricingController", ["$scope", "$state", '$uibModal', 'TrainingsPricing', '$filter', 'Credit', 'Pricing', 'Plan', 'Coupon', 'plans', 'groups', 'growl', 'machinesPricesPromise', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', 'couponsPromise', '_t'
|
|
, ($scope, $state, $uibModal, TrainingsPricing, $filter, Credit, Pricing, Plan, Coupon, plans, groups, growl, machinesPricesPromise, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, couponsPromise, _t) ->
|
|
|
|
### PUBLIC SCOPE ###
|
|
## List of machines prices (not considering any plan)
|
|
$scope.machinesPrices = machinesPricesPromise
|
|
|
|
## List of trainings pricing
|
|
$scope.trainingsPricings = trainingsPricingsPromise
|
|
|
|
## List of available subscriptions plans (eg. student/month, PME/year ...)
|
|
$scope.plans = plans
|
|
|
|
## List of groups (eg. normal, student ...)
|
|
$scope.groups = groups
|
|
|
|
## Associate free machine hours with subscriptions
|
|
$scope.machineCredits = machineCreditsPromise
|
|
|
|
## Array of associations (plan <-> training)
|
|
$scope.trainingCredits = trainingCreditsPromise
|
|
|
|
## Associate a plan with all its trainings ids
|
|
$scope.trainingCreditsGroups = {}
|
|
|
|
## List of trainings
|
|
$scope.trainings = trainingsPromise
|
|
|
|
## List of machines
|
|
$scope.machines = machinesPromise
|
|
|
|
## List of coupons
|
|
$scope.coupons = couponsPromise
|
|
|
|
## The plans list ordering. Default: by group
|
|
$scope.orderPlans = 'group_id'
|
|
|
|
## Status of the drop-down menu in Credits tab
|
|
$scope.status =
|
|
isopen: false
|
|
|
|
|
|
|
|
$scope.findTrainingsPricing = (trainingsPricings, trainingId, groupId)->
|
|
for trainingsPricing in trainingsPricings
|
|
if trainingsPricing.training_id == trainingId and trainingsPricing.group_id == groupId
|
|
return trainingsPricing
|
|
|
|
|
|
$scope.updateTrainingsPricing = (data, trainingsPricing)->
|
|
if data?
|
|
TrainingsPricing.update({ id: trainingsPricing.id }, { trainings_pricing: { amount: data } }).$promise
|
|
else
|
|
_t('please_specify_a_number')
|
|
|
|
##
|
|
# Retrieve a plan from its given identifier and returns it
|
|
# @param id {number} plan ID
|
|
# @returns {Object} Plan, inherits from $resource
|
|
##
|
|
$scope.getPlanFromId = (id) ->
|
|
for plan in $scope.plans
|
|
if plan.id == parseInt(id)
|
|
return plan
|
|
|
|
|
|
|
|
##
|
|
# Retrieve a group from its given identifier and returns it
|
|
# @param id {number} group ID
|
|
# @returns {Object} Group, inherits from $resource
|
|
##
|
|
$scope.getGroupFromId = (groups, id) ->
|
|
for group in groups
|
|
if group.id == parseInt(id)
|
|
return group
|
|
|
|
|
|
##
|
|
# Returns a human readable string of named trainings, according to the provided array.
|
|
# $scope.trainings may contains the full list of training. The returned string will only contains the trainings
|
|
# whom ID are given in the provided parameter
|
|
# @param trainings {Array<number>} trainings IDs array
|
|
##
|
|
$scope.showTrainings = (trainings) ->
|
|
unless angular.isArray(trainings) and trainings.length > 0
|
|
return _t('none')
|
|
|
|
selected = []
|
|
angular.forEach $scope.trainings, (t) ->
|
|
if trainings.indexOf(t.id) >= 0
|
|
selected.push t.name
|
|
return if selected.length then selected.join(' | ') else _t('none')
|
|
|
|
|
|
|
|
##
|
|
# Validation callback when editing training's credits. Save the changes.
|
|
# @param newdata {Object} training and associated plans
|
|
# @param planId {number|string} plan id
|
|
##
|
|
$scope.saveTrainingCredits = (newdata, planId) ->
|
|
# save the number of credits
|
|
Plan.update {id: planId},
|
|
training_credit_nb: newdata.training_credits
|
|
, angular.noop() # do nothing in case of success
|
|
, (error) ->
|
|
growl.error(_t('an_error_occurred_while_saving_the_number_of_credits'))
|
|
|
|
# save the associated trainings
|
|
angular.forEach $scope.trainingCreditsGroups, (original, key) ->
|
|
if parseInt(key) == parseInt(planId) # we've got the original data
|
|
if original.join('_') != newdata.training_ids.join('_') # if any changes
|
|
# iterate through the previous credits to remove
|
|
angular.forEach original, (oldTrainingId) ->
|
|
if newdata.training_ids.indexOf(oldTrainingId) == -1
|
|
tc = findTrainingCredit(oldTrainingId, planId)
|
|
if tc
|
|
tc.$delete {}
|
|
, ->
|
|
$scope.trainingCredits.splice($scope.trainingCredits.indexOf(tc), 1)
|
|
$scope.trainingCreditsGroups[planId].splice($scope.trainingCreditsGroups[planId].indexOf(tc.id), 1)
|
|
, (error) ->
|
|
growl.error(_t('an_error_occurred_while_deleting_credit_with_the_TRAINING', {TRAINING:tc.creditable.name}))
|
|
else
|
|
growl.error(_t('an_error_occurred_unable_to_find_the_credit_to_revoke'))
|
|
|
|
# iterate through the new credits to add
|
|
angular.forEach newdata.training_ids, (newTrainingId) ->
|
|
if original.indexOf(newTrainingId) == -1
|
|
Credit.save
|
|
credit:
|
|
creditable_id: newTrainingId
|
|
creditable_type: 'Training'
|
|
plan_id: planId
|
|
, (newTc) -> # success
|
|
$scope.trainingCredits.push(newTc)
|
|
$scope.trainingCreditsGroups[newTc.plan_id].push(newTc.creditable_id)
|
|
, (error) -> # failed
|
|
training = getTrainingFromId(newTrainingId)
|
|
growl.error(_t('an_error_occurred_while_creating_credit_with_the_TRAINING', {TRAINING: training.name}))
|
|
console.error(error)
|
|
|
|
|
|
|
|
|
|
##
|
|
# Cancel the current training credit modification
|
|
# @param rowform {Object} see http://vitalets.github.io/angular-xeditable/
|
|
##
|
|
$scope.cancelTrainingCredit = (rowform) ->
|
|
rowform.$cancel()
|
|
|
|
|
|
##
|
|
# Create a new empty entry in the $scope.machineCredits array
|
|
# @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
|
|
##
|
|
$scope.addMachineCredit = (e)->
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
$scope.inserted =
|
|
creditable_type: 'Machine'
|
|
$scope.machineCredits.push($scope.inserted)
|
|
$scope.status.isopen = !$scope.status.isopen
|
|
|
|
|
|
|
|
##
|
|
# In the Credits tab, while editing a machine credit row, select the current machine from the
|
|
# drop-down list of machines as the current item.
|
|
# @param credit {Object} credit object, inherited from $resource
|
|
##
|
|
$scope.showCreditableName = (credit) ->
|
|
selected = _t('not_set')
|
|
if credit and credit.creditable_id
|
|
angular.forEach $scope.machines, (m)->
|
|
if m.id == credit.creditable_id
|
|
selected = m.name+' ( id. '+m.id+' )'
|
|
return selected
|
|
|
|
|
|
|
|
##
|
|
# Validation callback when editing machine's credits. Save the changes.
|
|
# This will prevent the creation of two credits associating the same machine and plan.
|
|
# @param data {Object} machine, associated plan and number of credit hours.
|
|
# @param [id] {number} credit id for edition, create a new credit object if not provided
|
|
##
|
|
$scope.saveMachineCredit = (data, id) ->
|
|
for mc in $scope.machineCredits
|
|
if mc.plan_id == data.plan_id and mc.creditable_id == data.creditable_id and (id == null or mc.id != id)
|
|
growl.error(_t('error_a_credit_linking_this_machine_with_that_subscription_already_exists'))
|
|
unless id
|
|
$scope.machineCredits.pop()
|
|
return false
|
|
|
|
if id?
|
|
Credit.update {id: id}, credit: data, ->
|
|
growl.success(_t('changes_have_been_successfully_saved'))
|
|
else
|
|
data.creditable_type = 'Machine'
|
|
Credit.save
|
|
credit: data
|
|
, (resp) ->
|
|
$scope.machineCredits[$scope.machineCredits.length-1].id = resp.id
|
|
growl.success(_t('credit_was_successfully_saved'))
|
|
|
|
|
|
##
|
|
# Removes the newly inserted but not saved machine credit / Cancel the current machine credit modification
|
|
# @param rowform {Object} see http://vitalets.github.io/angular-xeditable/
|
|
# @param index {number} theme index in the $scope.machineCredits array
|
|
##
|
|
$scope.cancelMachineCredit = (rowform, index) ->
|
|
if $scope.machineCredits[index].id?
|
|
rowform.$cancel()
|
|
else
|
|
$scope.machineCredits.splice(index, 1)
|
|
|
|
|
|
|
|
##
|
|
# Deletes the machine credit at the specified index
|
|
# @param index {number} machine credit index in the $scope.machineCredits array
|
|
##
|
|
$scope.removeMachineCredit = (index) ->
|
|
Credit.delete $scope.machineCredits[index]
|
|
$scope.machineCredits.splice(index, 1)
|
|
|
|
|
|
|
|
##
|
|
# If the plan does not have a type, return a default value for display purposes
|
|
# @param type {string|undefined|null} plan's type (eg. 'partner')
|
|
# @returns {string}
|
|
##
|
|
$scope.getPlanType = (type) ->
|
|
if type == 'PartnerPlan'
|
|
return _t('partner')
|
|
else return _t('standard')
|
|
|
|
##
|
|
# Change the plans ordering criterion to the one provided
|
|
# @param orderBy {string} ordering criterion
|
|
##
|
|
$scope.setOrderPlans = (orderBy) ->
|
|
if $scope.orderPlans == orderBy
|
|
$scope.orderPlans = '-'+orderBy
|
|
else
|
|
$scope.orderPlans = orderBy
|
|
|
|
##
|
|
# Retrieve a price from prices array by a machineId and a groupId
|
|
##
|
|
$scope.findPriceBy = (prices, machineId, groupId)->
|
|
for price in prices
|
|
if price.priceable_id == machineId and price.group_id == groupId
|
|
return price
|
|
|
|
##
|
|
# update a price for a machine and a group, not considering any plan
|
|
##
|
|
$scope.updatePrice = (data, price)->
|
|
if data?
|
|
Price.update({ id: price.id }, { price: { amount: data } }).$promise
|
|
else
|
|
_t('please_specify_a_number')
|
|
|
|
##
|
|
# Delete the specified subcription plan
|
|
# @param id {number} plan id
|
|
##
|
|
$scope.deletePlan = (plans, id) ->
|
|
if typeof id != 'number'
|
|
console.error('[EditPricingController::deletePlan] Error: invalid id parameter')
|
|
else
|
|
# open a confirmation dialog
|
|
dialogs.confirm
|
|
resolve:
|
|
object: ->
|
|
title: _t('confirmation_required')
|
|
msg: _t('do_you_really_want_to_delete_this_subscription_plan')
|
|
, ->
|
|
# the admin has confirmed, delete the plan
|
|
Plan.delete {id: id}, (res) ->
|
|
growl.success(_t('subscription_plan_was_successfully_deleted'))
|
|
$scope.plans.splice(findItemIdxById(plans, id), 1)
|
|
|
|
, (error) ->
|
|
console.error('[EditPricingController::deletePlan] Error: '+error.statusText) if error.statusText
|
|
growl.error(_t('unable_to_delete_the_specified_subscription_an_error_occurred'))
|
|
|
|
|
|
|
|
##
|
|
# Generate a string identifying the given plan by literal humain-readable name
|
|
# @param plan {Object} Plan object, as recovered from GET /api/plan/:id
|
|
# @param groups {Array} List of Groups objects, as recovered from GET /api/groups
|
|
# @param short {boolean} If true, the generated name will contains the group slug, otherwise the group full name
|
|
# will be included.
|
|
# @returns {String}
|
|
##
|
|
$scope.humanReadablePlanName = (plan, groups, short)->
|
|
"#{$filter('humanReadablePlanName')(plan, groups, short)}"
|
|
|
|
|
|
|
|
##
|
|
# Delete a coupon from the server's database and, in case of success, from the list in memory
|
|
# @param coupons {Array<Object>} should be called with $scope.coupons
|
|
# @param id {number} ID of the coupon to delete
|
|
##
|
|
$scope.deleteCoupon = (coupons, id) ->
|
|
if typeof id != 'number'
|
|
console.error('[EditPricingController::deleteCoupon] Error: invalid id parameter')
|
|
else
|
|
# open a confirmation dialog
|
|
dialogs.confirm
|
|
resolve:
|
|
object: ->
|
|
title: _t('confirmation_required')
|
|
msg: _t('do_you_really_want_to_delete_this_coupon')
|
|
, ->
|
|
# the admin has confirmed, delete the coupon
|
|
Coupon.delete {id: id}, (res) ->
|
|
growl.success(_t('coupon_was_successfully_deleted'))
|
|
$scope.coupons.splice(findItemIdxById(coupons, id), 1)
|
|
|
|
, (error) ->
|
|
console.error('[EditPricingController::deleteCoupon] Error: '+error.statusText) if error.statusText
|
|
if error.status == 422
|
|
growl.error(_t('unable_to_delete_the_specified_coupon_already_in_use'))
|
|
else
|
|
growl.error(_t('unable_to_delete_the_specified_coupon_an_unexpected_error_occurred'))
|
|
|
|
|
|
|
|
##
|
|
# Open a modal allowing to select an user and send him the details of the provided coupon
|
|
# @param coupon {Object} The coupon to send
|
|
##
|
|
$scope.sendCouponToUser = (coupon) ->
|
|
$uibModal.open
|
|
templateUrl: '<%= asset_path "admin/pricing/sendCoupon.html" %>'
|
|
resolve:
|
|
coupon: -> coupon
|
|
size: 'md'
|
|
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 = ->
|
|
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')
|
|
]
|
|
|
|
|
|
### PRIVATE SCOPE ###
|
|
|
|
##
|
|
# Kind of constructor: these actions will be realized first when the controller is loaded
|
|
##
|
|
initialize = ->
|
|
|
|
$scope.trainingCreditsGroups = groupCreditsByPlan($scope.trainingCredits)
|
|
|
|
## adds empty array for plan which hasn't any credits yet
|
|
for plan in $scope.plans
|
|
unless $scope.trainingCreditsGroups[plan.id]?
|
|
$scope.trainingCreditsGroups[plan.id] = []
|
|
|
|
|
|
|
|
##
|
|
# Retrieve an item index by its ID from the given array of objects
|
|
# @param items {Array<{id:number}>}
|
|
# @param id {number}
|
|
# @returns {number} item index in the provided array
|
|
##
|
|
findItemIdxById = (items, id)->
|
|
(items.map (item)->
|
|
item.id
|
|
).indexOf(id)
|
|
|
|
|
|
|
|
##
|
|
# Group the given credits array into a map associating the plan ID with its associated trainings/machines
|
|
# @return {Object} the association map
|
|
##
|
|
groupCreditsByPlan = (credits) ->
|
|
creditsMap = {}
|
|
angular.forEach credits, (c) ->
|
|
unless creditsMap[c.plan_id]
|
|
creditsMap[c.plan_id] = []
|
|
creditsMap[c.plan_id].push(c.creditable_id)
|
|
creditsMap
|
|
|
|
|
|
|
|
##
|
|
# Iterate through $scope.traininfCredits to find the credit matching the given criterion
|
|
# @param trainingId {number|string} training ID
|
|
# @param planId {number|string} plan ID
|
|
##
|
|
findTrainingCredit = (trainingId, planId) ->
|
|
trainingId = parseInt(trainingId)
|
|
planId = parseInt(planId)
|
|
|
|
for credit in $scope.trainingCredits
|
|
if credit.plan_id == planId and credit.creditable_id == trainingId
|
|
return credit
|
|
|
|
|
|
##
|
|
# Retrieve a training from its given identifier and returns it
|
|
# @param id {number} training ID
|
|
# @returns {Object} Training inherited from $resource
|
|
##
|
|
getTrainingFromId = (id) ->
|
|
for training in $scope.trainings
|
|
if training.id == parseInt(id)
|
|
return training
|
|
|
|
|
|
## !!! MUST BE CALLED AT THE END of the controller
|
|
initialize()
|
|
]
|