mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-19 13:54:25 +01:00
improve slot is only subscription
This commit is contained in:
parent
870a092a81
commit
b559d10b87
@ -18,8 +18,8 @@
|
||||
* Controller used in the calendar management page
|
||||
*/
|
||||
|
||||
Application.Controllers.controller('AdminCalendarController', ['$scope', '$state', '$uibModal', 'moment', 'Availability', 'Slot', 'Setting', 'Export', 'growl', 'dialogs', 'bookingWindowStart', 'bookingWindowEnd', 'machinesPromise', '_t', 'uiCalendarConfig', 'CalendarConfig',
|
||||
function ($scope, $state, $uibModal, moment, Availability, Slot, Setting, Export, growl, dialogs, bookingWindowStart, bookingWindowEnd, machinesPromise, _t, uiCalendarConfig, CalendarConfig) {
|
||||
Application.Controllers.controller('AdminCalendarController', ['$scope', '$state', '$uibModal', 'moment', 'Availability', 'Slot', 'Setting', 'Export', 'growl', 'dialogs', 'bookingWindowStart', 'bookingWindowEnd', 'machinesPromise', 'plansPromise', 'groupsPromise', '_t', 'uiCalendarConfig', 'CalendarConfig',
|
||||
function ($scope, $state, $uibModal, moment, Availability, Slot, Setting, Export, growl, dialogs, bookingWindowStart, bookingWindowEnd, machinesPromise, plansPromise, groupsPromise, _t, uiCalendarConfig, CalendarConfig) {
|
||||
/* PRIVATE STATIC CONSTANTS */
|
||||
|
||||
// The calendar is divided in slots of 30 minutes
|
||||
@ -164,6 +164,44 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Open a confirmation modal to remove a plan for the currently selected availability,
|
||||
* @param plan {Object} must contain the machine ID and name
|
||||
*/
|
||||
$scope.removePlan = function (plan) {
|
||||
// open a confirmation dialog
|
||||
return dialogs.confirm({
|
||||
resolve: {
|
||||
object () {
|
||||
return {
|
||||
title: _t('app.admin.calendar.confirmation_required'),
|
||||
msg: _t('app.admin.calendar.do_you_really_want_to_remove_PLAN_from_this_slot', { GENDER: getGender($scope.currentUser), PLAN: plan.name }) + ' ' +
|
||||
_t('app.admin.calendar.this_will_prevent_any_new_reservation_on_this_slot_but_wont_cancel_those_existing') + '<br><strong>' +
|
||||
_t('app.admin.calendar.beware_this_cannot_be_reverted') + '</strong>'
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
, function () {
|
||||
// the admin has confirmed, remove the plan
|
||||
const plans = _.drop($scope.availability.plan_ids, plan.id);
|
||||
|
||||
return Availability.update({ id: $scope.availability.id }, { availability: { plans_attributes: [{ id: plan.id, _destroy: true }] } }
|
||||
, function (data, status) { // success
|
||||
// update the plan_ids attribute
|
||||
$scope.availability.plan_ids = data.plan_ids;
|
||||
$scope.availability.plans = availabilityPlans();
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents');
|
||||
// notify the admin
|
||||
return growl.success(_t('app.admin.calendar.the_plan_was_successfully_removed_from_the_slot'));
|
||||
}
|
||||
, function (data, status) { // failed
|
||||
growl.error(_t('app.admin.calendar.deletion_failed'));
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback to alert the admin that the export request was acknowledged and is
|
||||
* processing right now.
|
||||
@ -265,6 +303,26 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
} else { return 'other'; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a list of plans classified by group
|
||||
*
|
||||
* @returns {array}
|
||||
*/
|
||||
var availabilityPlans = function() {
|
||||
const plansClassifiedByGroup = [];
|
||||
const _plans = _.filter(plansPromise, function (p) { return _.include($scope.availability.plan_ids, p.id) });
|
||||
for (let group of Array.from(groupsPromise)) {
|
||||
const groupObj = { id: group.id, name: group.name, plans: [] };
|
||||
for (let plan of Array.from(_plans)) {
|
||||
if (plan.group_id === group.id) { groupObj.plans.push(plan); }
|
||||
}
|
||||
if (groupObj.plans.length > 0) {
|
||||
plansClassifiedByGroup.push(groupObj);
|
||||
}
|
||||
}
|
||||
return plansClassifiedByGroup;
|
||||
};
|
||||
|
||||
// Triggered when the admin drag on the agenda to create a new reservable slot.
|
||||
// @see http://fullcalendar.io/docs/selection/select_callback/
|
||||
//
|
||||
@ -316,7 +374,8 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
borderColor: availability.borderColor,
|
||||
tag_ids: availability.tag_ids,
|
||||
tags: availability.tags,
|
||||
machine_ids: availability.machine_ids
|
||||
machine_ids: availability.machine_ids,
|
||||
plan_ids: availability.plan_ids
|
||||
},
|
||||
true
|
||||
);
|
||||
@ -333,6 +392,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
||||
*/
|
||||
var calendarEventClickCb = function (event, jsEvent, view) {
|
||||
$scope.availability = event;
|
||||
$scope.availability.plans = availabilityPlans();
|
||||
|
||||
if ($scope.availabilityDom) {
|
||||
$scope.availabilityDom.classList.remove("fc-selected")
|
||||
|
@ -138,41 +138,53 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
if (Object.keys($scope.user).length > 0) {
|
||||
|
||||
// check user was selected a plan if slot is restricted for subscriptions
|
||||
const slotHasPlan = [];
|
||||
const slotValidations = [];
|
||||
let slotNotValid;
|
||||
let slotNotValidError;
|
||||
$scope.events.reserved.forEach(function (slot) {
|
||||
if (slot.plan_ids.length > 0) {
|
||||
if (
|
||||
($scope.selectedPlan && _.include(slot.plan_ids, $scope.selectedPlan.id)) ||
|
||||
($scope.user.subscribed_plan && _.include(slot.plan_ids, $scope.user.subscribed_plan.id))
|
||||
) {
|
||||
slotHasPlan.push(true);
|
||||
slotValidations.push(true);
|
||||
} else {
|
||||
slotHasPlan.push(false);
|
||||
slotNotValid = slot;
|
||||
if ($scope.selectedPlan && !_.include(slot.plan_ids, $scope.selectedPlan.id)) {
|
||||
slotNotValidError = 'selectedPlanError';
|
||||
}
|
||||
if ($scope.user.subscribed_plan && !_.include(slot.plan_ids, $scope.user.subscribed_plan.id)) {
|
||||
slotNotValidError = 'userPlanError';
|
||||
}
|
||||
if (!$scope.selectedPlan || !$scope.user.subscribed_plan) {
|
||||
slotNotValidError = 'noPlanError';
|
||||
}
|
||||
slotValidations.push(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
const hasPlanForSlot = slotHasPlan.every(function (a) { return a });
|
||||
const hasPlanForSlot = slotValidations.every(function (a) { return a; });
|
||||
if (!hasPlanForSlot) {
|
||||
return growl.error(_t('app.shared.cart.slot_restrict_subscriptions_must_select_plan'));
|
||||
}
|
||||
|
||||
|
||||
const reservation = mkReservation($scope.user, $scope.events.reserved, $scope.selectedPlan);
|
||||
|
||||
return Wallet.getWalletByUser({ user_id: $scope.user.id }, function (wallet) {
|
||||
const amountToPay = helpers.getAmountToPay($scope.amountTotal, wallet.amount);
|
||||
if (!$scope.isAdmin() && (amountToPay > 0)) {
|
||||
if ($rootScope.fablabWithoutOnlinePayment) {
|
||||
growl.error(_t('app.shared.cart.online_payment_disabled'));
|
||||
} else {
|
||||
return payByStripe(reservation);
|
||||
}
|
||||
if (!$scope.isAdmin()) {
|
||||
return growl.error(_t('app.shared.cart.slot_restrict_subscriptions_must_select_plan'));
|
||||
} else {
|
||||
if ($scope.isAdmin() || (amountToPay === 0)) {
|
||||
return payOnSite(reservation);
|
||||
}
|
||||
const modalInstance = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: '<%= asset_path "shared/_reserve_slot_without_plan.html" %>',
|
||||
size: 'md',
|
||||
controller: 'ReserveSlotWithoutPlanController',
|
||||
resolve: {
|
||||
slot: function() { return slotNotValid; },
|
||||
slotNotValidError: function() { return slotNotValidError; },
|
||||
}
|
||||
});
|
||||
modalInstance.result.then(function(res) {
|
||||
return paySlots();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return paySlots();
|
||||
}
|
||||
} else {
|
||||
// otherwise we alert, this error musn't occur when the current user is not admin
|
||||
return growl.error(_t('app.shared.cart.please_select_a_member_first'));
|
||||
@ -289,15 +301,21 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
if ($scope.slot.plan_ids.length > 0) {
|
||||
const _plans = _.filter($scope.plans, function (p) { return _.include($scope.slot.plan_ids, p.id) });
|
||||
$scope.slot.plansGrouped = [];
|
||||
$scope.slot.group_ids = [];
|
||||
for (let group of Array.from($scope.groups)) {
|
||||
const groupObj = { id: group.id, name: group.name, plans: [] };
|
||||
for (let plan of Array.from(_plans)) {
|
||||
if (plan.group_id === group.id) { groupObj.plans.push(plan); }
|
||||
}
|
||||
if (groupObj.plans.length > 0) {
|
||||
$scope.slot.plansGrouped.push(groupObj);
|
||||
if ($scope.isAdmin()) {
|
||||
$scope.slot.plansGrouped.push(groupObj);
|
||||
} else if ($scope.user.group_id === groupObj.id) {
|
||||
$scope.slot.plansGrouped.push(groupObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
$scope.slot.group_ids = $scope.slot.plansGrouped.map(function(g) { return g.id; });
|
||||
}
|
||||
|
||||
if (!$scope.slot.is_reserved && !$scope.events.modifiable && !$scope.slot.is_completed) {
|
||||
@ -646,9 +664,53 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs',
|
||||
return $scope.selectedPlan = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Actions to pay slots
|
||||
*/
|
||||
var paySlots = function() {
|
||||
const reservation = mkReservation($scope.user, $scope.events.reserved, $scope.selectedPlan);
|
||||
|
||||
return Wallet.getWalletByUser({ user_id: $scope.user.id }, function (wallet) {
|
||||
const amountToPay = helpers.getAmountToPay($scope.amountTotal, wallet.amount);
|
||||
if (!$scope.isAdmin() && (amountToPay > 0)) {
|
||||
if ($rootScope.fablabWithoutOnlinePayment) {
|
||||
growl.error(_t('app.shared.cart.online_payment_disabled'));
|
||||
} else {
|
||||
return payByStripe(reservation);
|
||||
}
|
||||
} else {
|
||||
if ($scope.isAdmin() || (amountToPay === 0)) {
|
||||
return payOnSite(reservation);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// !!! MUST BE CALLED AT THE END of the directive
|
||||
return initialize();
|
||||
}
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
/**
|
||||
* Controller used to alert admin reserve slot without plan
|
||||
*/
|
||||
Application.Controllers.controller('ReserveSlotWithoutPlanController', ['$scope', '$uibModalInstance', 'slot', 'slotNotValidError', 'growl', '_t',
|
||||
function ($scope, $uibModalInstance, slot, slotNotValidError, growl, _t) {
|
||||
$scope.slot = slot;
|
||||
$scope.slotNotValidError = slotNotValidError;
|
||||
/**
|
||||
* Confirmation callback
|
||||
*/
|
||||
$scope.ok = function () {
|
||||
$uibModalInstance.close({});
|
||||
}
|
||||
/**
|
||||
* Cancellation callback
|
||||
*/
|
||||
$scope.cancel = function () {
|
||||
$uibModalInstance.dismiss('cancel');
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
@ -584,7 +584,9 @@ angular.module('application.router', ['ui.router'])
|
||||
resolve: {
|
||||
bookingWindowStart: ['Setting', function (Setting) { return Setting.get({ name: 'booking_window_start' }).$promise; }],
|
||||
bookingWindowEnd: ['Setting', function (Setting) { return Setting.get({ name: 'booking_window_end' }).$promise; }],
|
||||
machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }]
|
||||
machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],
|
||||
plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],
|
||||
groupsPromise: ['Group', function (Group) { return Group.query().$promise; }]
|
||||
}
|
||||
})
|
||||
.state('app.admin.calendar.icalendar', {
|
||||
|
@ -84,6 +84,25 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="widget panel b-a m m-t-lg" ng-if="availability.plan_ids.length > 0">
|
||||
<div class="panel-heading b-b small">
|
||||
<h3 translate>{{ 'app.admin.calendar.plans' }}</h3>
|
||||
</div>
|
||||
<div class="widget-content no-bg auto wrapper">
|
||||
<ul class="list-unstyled">
|
||||
<li ng-repeat="g in availability.plans" class="m-b-xs">
|
||||
<div class="font-sbold">{{::g.name}}</div>
|
||||
<ul class="m-n" ng-repeat="plan in g.plans">
|
||||
<li>
|
||||
{{::plan.name}}
|
||||
<span class="btn btn-warning btn-xs" ng-click="removePlan(plan)" ><i class="fa fa-times red"></i></span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="widget panel b-a m m-t-lg" ng-if="availability" >
|
||||
<div class="panel-heading b-b small">
|
||||
<h3 translate>{{ 'app.admin.calendar.actions' }}</h3>
|
||||
|
@ -28,17 +28,22 @@
|
||||
switch-animate="true"
|
||||
switch-readonly="{{slot.isValid}}"/>
|
||||
</div>
|
||||
<div class="alert alert-warning m-t-sm m-b-none" ng-show="slot.plansGrouped.length">
|
||||
<div class="font-sbold text-u-c" translate>{{ 'app.shared.cart.slot_restrict_plans' }}</div>
|
||||
<div ng-repeat="group in slot.plansGrouped">
|
||||
<div class="font-sbold">{{::group.name}}</div>
|
||||
<ul class="m-n" ng-repeat="plan in group.plans">
|
||||
<li>{{::plan.name}}</li>
|
||||
</ul>
|
||||
<div class="alert alert-warning m-t-sm m-b-none" ng-show="slot.plan_ids.length > 0">
|
||||
<div ng-show="slot.plansGrouped.length > 0">
|
||||
<div class="font-sbold text-u-c" translate>{{ 'app.shared.cart.slot_restrict_plans' }}</div>
|
||||
<div ng-repeat="group in slot.plansGrouped">
|
||||
<div class="font-sbold">{{::group.name}}</div>
|
||||
<ul class="m-n" ng-repeat="plan in group.plans">
|
||||
<li>{{::plan.name}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="slot.plansGrouped.length === 0">
|
||||
<div class="font-sbold text-u-c" translate>{{ 'app.shared.cart.slot_restrict_plans_of_others_groups' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div ng-hide="slot.plan_ids.length > 0 && slot.plansGrouped.length === 0">
|
||||
<button class="btn btn-valid btn-warning btn-block text-u-c r-b" ng-click="validateSlot(slot)" ng-if="!slot.isValid" translate>{{ 'app.shared.cart.confirm_this_slot' }}</button>
|
||||
</div>
|
||||
|
||||
|
22
app/assets/templates/shared/_reserve_slot_without_plan.html
Normal file
22
app/assets/templates/shared/_reserve_slot_without_plan.html
Normal file
@ -0,0 +1,22 @@
|
||||
<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 ng-show="slotNotValidError === 'selectedPlanError'" translate>{{ 'app.shared.cart.selected_plan_dont_match_slot' }}</h1>
|
||||
<h1 ng-show="slotNotValidError === 'userPlanError'" translate>{{ 'app.shared.cart.user_plan_dont_match_slot' }}</h1>
|
||||
<h1 ng-show="slotNotValidError === 'noPlanError'" translate>{{ 'app.shared.cart.no_plan_match_slot' }}</h1>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="font-sbold text-u-c">{{ 'app.shared.cart.datetime_to_time' | translate:{START_DATETIME:(slot.start | amDateFormat:'LLLL'), END_TIME:(slot.end | amDateFormat:'LT') } }}</div>
|
||||
<div class="alert alert-warning m-t-sm m-b-none" ng-show="slot.plan_ids.length > 0">
|
||||
<div class="font-sbold text-u-c" translate>{{ 'app.shared.cart.slot_restrict_plans' }}</div>
|
||||
<div ng-repeat="group in slot.plansGrouped">
|
||||
<div class="font-sbold">{{::group.name}}</div>
|
||||
<ul class="m-n" ng-repeat="plan in group.plans">
|
||||
<li>{{::plan.name}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-info" ng-click="ok()" translate>{{ 'app.shared.buttons.confirm' }}</button>
|
||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
||||
</div>
|
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.array!(@availabilities) do |availability|
|
||||
json.id availability.id
|
||||
json.title availability.title
|
||||
@ -15,4 +17,5 @@ json.array!(@availabilities) do |availability|
|
||||
json.name t.name
|
||||
end
|
||||
json.lock availability.lock
|
||||
json.plan_ids availability.plan_ids
|
||||
end
|
||||
|
@ -5,10 +5,11 @@ json.start_at @availability.start_at.iso8601
|
||||
json.end_at @availability.end_at.iso8601
|
||||
json.available_type @availability.available_type
|
||||
json.machine_ids @availability.machine_ids
|
||||
json.plan_ids @availability.plan_ids
|
||||
json.backgroundColor 'white'
|
||||
json.borderColor availability_border_color(@availability)
|
||||
json.tag_ids @availability.tag_ids
|
||||
json.tags @availability.tags do |t|
|
||||
json.id t.id
|
||||
json.name t.name
|
||||
end
|
||||
end
|
||||
|
@ -32,6 +32,8 @@ en:
|
||||
beware_this_cannot_be_reverted: "Beware: this cannot be reverted."
|
||||
the_machine_was_successfully_removed_from_the_slot: "The machine was successfully removed from the slot."
|
||||
deletion_failed: "Deletion failed."
|
||||
do_you_really_want_to_remove_PLAN_from_this_slot: "Do you really want to remove \"{PLAN}\" from this slot?"
|
||||
the_plan_was_successfully_removed_from_the_slot: "The plan was successfully removed from the slot."
|
||||
DATE_slot: "{DATE} slot:"
|
||||
what_kind_of_slot_do_you_want_to_create: "What kind of slot do you want to create?"
|
||||
training: "Training"
|
||||
|
@ -30,6 +30,8 @@ es:
|
||||
beware_this_cannot_be_reverted: "Beware: esto no puede ser revertido."
|
||||
the_machine_was_successfully_removed_from_the_slot: "La máquina se eliminó correctamente de la ranura."
|
||||
deletion_failed: "Fallo al borrar."
|
||||
do_you_really_want_to_remove_PLAN_from_this_slot: "Do you really want to remove \"{PLAN}\" from this slot?"
|
||||
the_plan_was_successfully_removed_from_the_slot: "The plan was successfully removed from the slot."
|
||||
DATE_slot: "{DATE} espacio:"
|
||||
what_kind_of_slot_do_you_want_to_create: "¿Qué tipo de horario desea crear?"
|
||||
training: "Formación"
|
||||
|
@ -32,6 +32,8 @@ fr:
|
||||
beware_this_cannot_be_reverted: "Attention : ceci n'est pas réversible."
|
||||
the_machine_was_successfully_removed_from_the_slot: "La machine a bien été supprimée du créneau."
|
||||
deletion_failed: "La suppression a échouée."
|
||||
do_you_really_want_to_remove_PLAN_from_this_slot: "Êtes-vous {GENDER, select, female{sûre} other{sûr}} de vouloir retirer \"{PLAN}\" de ce créneau ?"
|
||||
the_plan_was_successfully_removed_from_the_slot: "Le formule d'abonnement a bien été supprimée du créneau."
|
||||
DATE_slot: "Créneau du {DATE} :"
|
||||
what_kind_of_slot_do_you_want_to_create: "Quel type de créneau voulez-vous créer ?"
|
||||
training: "Formation"
|
||||
|
@ -32,6 +32,8 @@ pt:
|
||||
beware_this_cannot_be_reverted: "Cuidado: isso não pode ser revertido."
|
||||
the_machine_was_successfully_removed_from_the_slot: "A máquina foi removida com sucesso desse slot."
|
||||
deletion_failed: "Falha ao deletar."
|
||||
do_you_really_want_to_remove_PLAN_from_this_slot: "Do you really want to remove \"{PLAN}\" from this slot?"
|
||||
the_plan_was_successfully_removed_from_the_slot: "The plan was successfully removed from the slot."
|
||||
DATE_slot: "{DATE} slot:"
|
||||
what_kind_of_slot_do_you_want_to_create: "Qual tipo de slot você deseja criar?"
|
||||
training: "Treinamento"
|
||||
|
@ -441,3 +441,7 @@ en:
|
||||
online_payment_disabled: "Online payment is not available. Please contact the Fablab reception directly."
|
||||
slot_restrict_plans: "This slot is restricted for the plans below:"
|
||||
slot_restrict_subscriptions_must_select_plan: "The slot is restricted for the subscribers. Please select a plan first."
|
||||
slot_restrict_plans_of_others_groups: "The slot is restricted for the subscribers of others groups."
|
||||
selected_plan_dont_match_slot: "Selected plan dont match this slot"
|
||||
user_plan_dont_match_slot: "User subscribed plan dont match this slot"
|
||||
no_plan_match_slot: "You dont have any plan to match this slot"
|
||||
|
@ -418,3 +418,7 @@ es:
|
||||
online_payment_disabled: "El pago en línea no está disponible. Póngase en contacto directamente con la recepción de Fablab."
|
||||
slot_restrict_plans: "This slot is restricted for the plans below:"
|
||||
slot_restrict_subscriptions_must_select_plan: "The slot is restricted for the subscribers. Please select a plan first."
|
||||
slot_restrict_plans_of_others_groups: "The slot is restricted for the subscribers of others groups."
|
||||
selected_plan_dont_match_slot: "Selected plan dont match this slot"
|
||||
user_plan_dont_match_slot: "User subscribed plan dont match this slot"
|
||||
no_plan_match_slot: "You dont have any plan to match this slot"
|
||||
|
@ -441,3 +441,7 @@ fr:
|
||||
online_payment_disabled: "Le payment par carte bancaire n'est pas disponible. Merci de contacter directement l'accueil du Fablab."
|
||||
slot_restrict_plans: "Ce créneau est restreint pour les formules d'abonnement ci-desous:"
|
||||
slot_restrict_subscriptions_must_select_plan: "Le créneau est restreint pour les abonnés. Veuillez tout d'abord sélectionner une formule d'abonnement"
|
||||
slot_restrict_plans_of_others_groups: "Ce créneau est restreint pour les abonnés d'autres groupes."
|
||||
selected_plan_dont_match_slot: "L'abonnement sélectionné ne correspondent pas ce créneau"
|
||||
user_plan_dont_match_slot: "L'abonnement du membre ne correspondent pas ce créneau"
|
||||
no_plan_match_slot: "Aucun abonnement correspondent ce créneau"
|
||||
|
@ -441,3 +441,7 @@ pt:
|
||||
online_payment_disabled: "O pagamento online não está disponível. Entre em contato diretamente com a recepção do Fablab."
|
||||
slot_restrict_plans: "This slot is restricted for the plans below:"
|
||||
slot_restrict_subscriptions_must_select_plan: "The slot is restricted for the subscribers. Please select a plan first."
|
||||
slot_restrict_plans_of_others_groups: "The slot is restricted for the subscribers of others groups."
|
||||
selected_plan_dont_match_slot: "Selected plan dont match this slot"
|
||||
user_plan_dont_match_slot: "User subscribed plan dont match this slot"
|
||||
no_plan_match_slot: "You dont have any plan to match this slot"
|
||||
|
Loading…
x
Reference in New Issue
Block a user